aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--BUILD18
-rw-r--r--CMakeLists.txt9
-rw-r--r--Makefile48
-rw-r--r--binding.gyp1
-rw-r--r--build.yaml16
-rw-r--r--config.m41
-rw-r--r--gRPC-Core.podspec5
-rw-r--r--grpc.def5
-rwxr-xr-xgrpc.gemspec3
-rw-r--r--include/grpc++/resource_quota.h70
-rw-r--r--include/grpc++/server_builder.h8
-rw-r--r--include/grpc++/support/channel_arguments.h8
-rw-r--r--include/grpc/grpc.h17
-rw-r--r--include/grpc/impl/codegen/grpc_types.h5
-rw-r--r--package.xml3
-rw-r--r--src/core/ext/client_channel/client_channel.c4
-rw-r--r--src/core/ext/client_channel/subchannel.c3
-rw-r--r--src/core/ext/client_channel/subchannel.h2
-rw-r--r--src/core/ext/lb_policy/pick_first/pick_first.c6
-rw-r--r--src/core/ext/lb_policy/round_robin/round_robin.c13
-rw-r--r--src/core/ext/transport/chttp2/client/insecure/channel_create.c3
-rw-r--r--src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c6
-rw-r--r--src/core/ext/transport/chttp2/client/secure/secure_channel_create.c6
-rw-r--r--src/core/ext/transport/chttp2/server/insecure/server_chttp2.c4
-rw-r--r--src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c8
-rw-r--r--src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c3
-rw-r--r--src/core/ext/transport/chttp2/transport/chttp2_transport.c169
-rw-r--r--src/core/ext/transport/chttp2/transport/internal.h20
-rw-r--r--src/core/ext/transport/chttp2/transport/stream_map.c11
-rw-r--r--src/core/ext/transport/chttp2/transport/stream_map.h3
-rw-r--r--src/core/lib/http/httpcli.c22
-rw-r--r--src/core/lib/http/httpcli.h2
-rw-r--r--src/core/lib/iomgr/endpoint.c4
-rw-r--r--src/core/lib/iomgr/endpoint.h4
-rw-r--r--src/core/lib/iomgr/endpoint_pair.h5
-rw-r--r--src/core/lib/iomgr/endpoint_pair_posix.c13
-rw-r--r--src/core/lib/iomgr/resource_quota.c714
-rw-r--r--src/core/lib/iomgr/resource_quota.h224
-rw-r--r--src/core/lib/iomgr/tcp_client.h5
-rw-r--r--src/core/lib/iomgr/tcp_client_posix.c50
-rw-r--r--src/core/lib/iomgr/tcp_client_posix.h45
-rw-r--r--src/core/lib/iomgr/tcp_posix.c80
-rw-r--r--src/core/lib/iomgr/tcp_posix.h4
-rw-r--r--src/core/lib/iomgr/tcp_server.h3
-rw-r--r--src/core/lib/iomgr/tcp_server_posix.c23
-rw-r--r--src/core/lib/security/credentials/google_default/google_default_credentials.c5
-rw-r--r--src/core/lib/security/credentials/jwt/jwt_verifier.c16
-rw-r--r--src/core/lib/security/credentials/oauth2/oauth2_credentials.c20
-rw-r--r--src/core/lib/security/transport/secure_endpoint.c7
-rw-r--r--src/core/lib/surface/call.c6
-rw-r--r--src/core/lib/surface/init.c2
-rw-r--r--src/cpp/common/channel_arguments.cc16
-rw-r--r--src/cpp/common/resource_quota_cc.cc51
-rw-r--r--src/cpp/server/server_builder.cc22
-rw-r--r--src/proto/grpc/testing/control.proto11
-rw-r--r--src/proto/grpc/testing/stats.proto8
-rw-r--r--src/python/grpcio/grpc_core_dependencies.py1
-rw-r--r--src/ruby/ext/grpc/rb_grpc_imports.generated.c10
-rw-r--r--src/ruby/ext/grpc/rb_grpc_imports.generated.h15
-rw-r--r--test/core/bad_client/bad_client.c5
-rw-r--r--test/core/end2end/end2end_nosec_tests.c8
-rw-r--r--test/core/end2end/end2end_tests.c8
-rw-r--r--test/core/end2end/fixtures/h2_sockpair+trace.c4
-rw-r--r--test/core/end2end/fixtures/h2_sockpair.c4
-rw-r--r--test/core/end2end/fixtures/h2_sockpair_1byte.c4
-rw-r--r--test/core/end2end/fixtures/http_proxy.c10
-rw-r--r--test/core/end2end/fuzzers/api_fuzzer.c16
-rw-r--r--test/core/end2end/fuzzers/client_fuzzer.c6
-rw-r--r--test/core/end2end/fuzzers/server_fuzzer.c6
-rwxr-xr-xtest/core/end2end/gen_build_yaml.py24
-rw-r--r--test/core/end2end/tests/max_message_length.c1
-rw-r--r--test/core/end2end/tests/network_status_change.c1
-rw-r--r--test/core/end2end/tests/resource_quota_server.c359
-rw-r--r--test/core/http/httpcli_test.c11
-rw-r--r--test/core/http/httpscli_test.c11
-rw-r--r--test/core/internal_api_canaries/iomgr.c1
-rw-r--r--test/core/iomgr/endpoint_pair_test.c6
-rw-r--r--test/core/iomgr/fd_conservation_posix_test.c6
-rw-r--r--test/core/iomgr/resource_quota_test.c749
-rw-r--r--test/core/iomgr/tcp_client_posix_test.c4
-rw-r--r--test/core/iomgr/tcp_posix_test.c36
-rw-r--r--test/core/iomgr/tcp_server_posix_test.c15
-rw-r--r--test/core/security/secure_endpoint_test.c5
-rw-r--r--test/core/surface/concurrent_connectivity_test.c2
-rw-r--r--test/core/util/mock_endpoint.c41
-rw-r--r--test/core/util/mock_endpoint.h3
-rw-r--r--test/core/util/passthru_endpoint.c34
-rw-r--r--test/core/util/passthru_endpoint.h3
-rw-r--r--test/core/util/port_server_client.c20
-rw-r--r--test/core/util/test_tcp_server.c4
-rw-r--r--test/cpp/end2end/end2end_test.cc39
-rw-r--r--test/cpp/qps/client.h57
-rw-r--r--test/cpp/qps/client_async.cc11
-rw-r--r--test/cpp/qps/client_sync.cc7
-rw-r--r--test/cpp/qps/driver.cc31
-rw-r--r--test/cpp/qps/report.cc6
-rw-r--r--test/cpp/qps/server_async.cc6
-rw-r--r--test/cpp/qps/server_sync.cc6
-rw-r--r--tools/doxygen/Doxyfile.c++1
-rw-r--r--tools/doxygen/Doxyfile.c++.internal2
-rw-r--r--tools/doxygen/Doxyfile.core.internal3
-rw-r--r--tools/run_tests/performance/scenario_config.py15
-rw-r--r--tools/run_tests/sources_and_headers.json27
-rw-r--r--tools/run_tests/tests.json834
-rw-r--r--vsprojects/buildtests_c.sln27
-rw-r--r--vsprojects/vcxproj/grpc++/grpc++.vcxproj3
-rw-r--r--vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters6
-rw-r--r--vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj3
-rw-r--r--vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters6
-rw-r--r--vsprojects/vcxproj/grpc/grpc.vcxproj4
-rw-r--r--vsprojects/vcxproj/grpc/grpc.vcxproj.filters9
-rw-r--r--vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj4
-rw-r--r--vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters9
-rw-r--r--vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj4
-rw-r--r--vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters9
-rw-r--r--vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj2
-rw-r--r--vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj.filters3
-rw-r--r--vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj2
-rw-r--r--vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj.filters3
-rw-r--r--vsprojects/vcxproj/test/resource_quota_test/resource_quota_test.vcxproj199
-rw-r--r--vsprojects/vcxproj/test/resource_quota_test/resource_quota_test.vcxproj.filters21
121 files changed, 4434 insertions, 198 deletions
diff --git a/BUILD b/BUILD
index 86cbf0c70d..7d9f1c53d6 100644
--- a/BUILD
+++ b/BUILD
@@ -204,6 +204,7 @@ cc_library(
"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",
@@ -212,6 +213,7 @@ cc_library(
"src/core/lib/iomgr/socket_utils_posix.h",
"src/core/lib/iomgr/socket_windows.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_uv.h",
@@ -375,6 +377,7 @@ cc_library(
"src/core/lib/iomgr/resolve_address_posix.c",
"src/core/lib/iomgr/resolve_address_uv.c",
"src/core/lib/iomgr/resolve_address_windows.c",
+ "src/core/lib/iomgr/resource_quota.c",
"src/core/lib/iomgr/sockaddr_utils.c",
"src/core/lib/iomgr/socket_utils_common_posix.c",
"src/core/lib/iomgr/socket_utils_linux.c",
@@ -625,6 +628,7 @@ cc_library(
"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",
@@ -633,6 +637,7 @@ cc_library(
"src/core/lib/iomgr/socket_utils_posix.h",
"src/core/lib/iomgr/socket_windows.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_uv.h",
@@ -781,6 +786,7 @@ cc_library(
"src/core/lib/iomgr/resolve_address_posix.c",
"src/core/lib/iomgr/resolve_address_uv.c",
"src/core/lib/iomgr/resolve_address_windows.c",
+ "src/core/lib/iomgr/resource_quota.c",
"src/core/lib/iomgr/sockaddr_utils.c",
"src/core/lib/iomgr/socket_utils_common_posix.c",
"src/core/lib/iomgr/socket_utils_linux.c",
@@ -1001,6 +1007,7 @@ cc_library(
"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",
@@ -1009,6 +1016,7 @@ cc_library(
"src/core/lib/iomgr/socket_utils_posix.h",
"src/core/lib/iomgr/socket_windows.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_uv.h",
@@ -1149,6 +1157,7 @@ cc_library(
"src/core/lib/iomgr/resolve_address_posix.c",
"src/core/lib/iomgr/resolve_address_uv.c",
"src/core/lib/iomgr/resolve_address_windows.c",
+ "src/core/lib/iomgr/resource_quota.c",
"src/core/lib/iomgr/sockaddr_utils.c",
"src/core/lib/iomgr/socket_utils_common_posix.c",
"src/core/lib/iomgr/socket_utils_linux.c",
@@ -1352,6 +1361,7 @@ cc_library(
"src/cpp/common/channel_filter.cc",
"src/cpp/common/completion_queue_cc.cc",
"src/cpp/common/core_codegen.cc",
+ "src/cpp/common/resource_quota_cc.cc",
"src/cpp/common/rpc_method.cc",
"src/cpp/server/async_generic_service.cc",
"src/cpp/server/create_default_thread_pool.cc",
@@ -1396,6 +1406,7 @@ cc_library(
"include/grpc++/impl/thd.h",
"include/grpc++/impl/thd_cxx11.h",
"include/grpc++/impl/thd_no_cxx11.h",
+ "include/grpc++/resource_quota.h",
"include/grpc++/security/auth_context.h",
"include/grpc++/security/auth_metadata_processor.h",
"include/grpc++/security/credentials.h",
@@ -1500,6 +1511,7 @@ cc_library(
"src/cpp/common/channel_filter.cc",
"src/cpp/common/completion_queue_cc.cc",
"src/cpp/common/core_codegen.cc",
+ "src/cpp/common/resource_quota_cc.cc",
"src/cpp/common/rpc_method.cc",
"src/cpp/server/async_generic_service.cc",
"src/cpp/server/create_default_thread_pool.cc",
@@ -1544,6 +1556,7 @@ cc_library(
"include/grpc++/impl/thd.h",
"include/grpc++/impl/thd_cxx11.h",
"include/grpc++/impl/thd_no_cxx11.h",
+ "include/grpc++/resource_quota.h",
"include/grpc++/security/auth_context.h",
"include/grpc++/security/auth_metadata_processor.h",
"include/grpc++/security/credentials.h",
@@ -1722,6 +1735,7 @@ cc_library(
"src/cpp/common/channel_filter.cc",
"src/cpp/common/completion_queue_cc.cc",
"src/cpp/common/core_codegen.cc",
+ "src/cpp/common/resource_quota_cc.cc",
"src/cpp/common/rpc_method.cc",
"src/cpp/server/async_generic_service.cc",
"src/cpp/server/create_default_thread_pool.cc",
@@ -1766,6 +1780,7 @@ cc_library(
"include/grpc++/impl/thd.h",
"include/grpc++/impl/thd_cxx11.h",
"include/grpc++/impl/thd_no_cxx11.h",
+ "include/grpc++/resource_quota.h",
"include/grpc++/security/auth_context.h",
"include/grpc++/security/auth_metadata_processor.h",
"include/grpc++/security/credentials.h",
@@ -2073,6 +2088,7 @@ objc_library(
"src/core/lib/iomgr/resolve_address_posix.c",
"src/core/lib/iomgr/resolve_address_uv.c",
"src/core/lib/iomgr/resolve_address_windows.c",
+ "src/core/lib/iomgr/resource_quota.c",
"src/core/lib/iomgr/sockaddr_utils.c",
"src/core/lib/iomgr/socket_utils_common_posix.c",
"src/core/lib/iomgr/socket_utils_linux.c",
@@ -2302,6 +2318,7 @@ objc_library(
"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",
@@ -2310,6 +2327,7 @@ objc_library(
"src/core/lib/iomgr/socket_utils_posix.h",
"src/core/lib/iomgr/socket_windows.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_uv.h",
diff --git a/CMakeLists.txt b/CMakeLists.txt
index af1bb5912a..0550a3b2ec 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -334,6 +334,7 @@ add_library(grpc
src/core/lib/iomgr/resolve_address_posix.c
src/core/lib/iomgr/resolve_address_uv.c
src/core/lib/iomgr/resolve_address_windows.c
+ src/core/lib/iomgr/resource_quota.c
src/core/lib/iomgr/sockaddr_utils.c
src/core/lib/iomgr/socket_utils_common_posix.c
src/core/lib/iomgr/socket_utils_linux.c
@@ -605,6 +606,7 @@ add_library(grpc_cronet
src/core/lib/iomgr/resolve_address_posix.c
src/core/lib/iomgr/resolve_address_uv.c
src/core/lib/iomgr/resolve_address_windows.c
+ src/core/lib/iomgr/resource_quota.c
src/core/lib/iomgr/sockaddr_utils.c
src/core/lib/iomgr/socket_utils_common_posix.c
src/core/lib/iomgr/socket_utils_linux.c
@@ -848,6 +850,7 @@ add_library(grpc_unsecure
src/core/lib/iomgr/resolve_address_posix.c
src/core/lib/iomgr/resolve_address_uv.c
src/core/lib/iomgr/resolve_address_windows.c
+ src/core/lib/iomgr/resource_quota.c
src/core/lib/iomgr/sockaddr_utils.c
src/core/lib/iomgr/socket_utils_common_posix.c
src/core/lib/iomgr/socket_utils_linux.c
@@ -1061,6 +1064,7 @@ add_library(grpc++
src/cpp/common/channel_filter.cc
src/cpp/common/completion_queue_cc.cc
src/cpp/common/core_codegen.cc
+ src/cpp/common/resource_quota_cc.cc
src/cpp/common/rpc_method.cc
src/cpp/server/async_generic_service.cc
src/cpp/server/create_default_thread_pool.cc
@@ -1122,6 +1126,7 @@ foreach(_hdr
include/grpc++/impl/thd.h
include/grpc++/impl/thd_cxx11.h
include/grpc++/impl/thd_no_cxx11.h
+ include/grpc++/resource_quota.h
include/grpc++/security/auth_context.h
include/grpc++/security/auth_metadata_processor.h
include/grpc++/security/credentials.h
@@ -1224,6 +1229,7 @@ add_library(grpc++_cronet
src/cpp/common/channel_filter.cc
src/cpp/common/completion_queue_cc.cc
src/cpp/common/core_codegen.cc
+ src/cpp/common/resource_quota_cc.cc
src/cpp/common/rpc_method.cc
src/cpp/server/async_generic_service.cc
src/cpp/server/create_default_thread_pool.cc
@@ -1285,6 +1291,7 @@ foreach(_hdr
include/grpc++/impl/thd.h
include/grpc++/impl/thd_cxx11.h
include/grpc++/impl/thd_no_cxx11.h
+ include/grpc++/resource_quota.h
include/grpc++/security/auth_context.h
include/grpc++/security/auth_metadata_processor.h
include/grpc++/security/credentials.h
@@ -1478,6 +1485,7 @@ add_library(grpc++_unsecure
src/cpp/common/channel_filter.cc
src/cpp/common/completion_queue_cc.cc
src/cpp/common/core_codegen.cc
+ src/cpp/common/resource_quota_cc.cc
src/cpp/common/rpc_method.cc
src/cpp/server/async_generic_service.cc
src/cpp/server/create_default_thread_pool.cc
@@ -1539,6 +1547,7 @@ foreach(_hdr
include/grpc++/impl/thd.h
include/grpc++/impl/thd_cxx11.h
include/grpc++/impl/thd_no_cxx11.h
+ include/grpc++/resource_quota.h
include/grpc++/security/auth_context.h
include/grpc++/security/auth_metadata_processor.h
include/grpc++/security/credentials.h
diff --git a/Makefile b/Makefile
index 89b9f053f8..d5bb63c16d 100644
--- a/Makefile
+++ b/Makefile
@@ -1008,6 +1008,7 @@ no_server_test: $(BINDIR)/$(CONFIG)/no_server_test
percent_decode_fuzzer: $(BINDIR)/$(CONFIG)/percent_decode_fuzzer
percent_encode_fuzzer: $(BINDIR)/$(CONFIG)/percent_encode_fuzzer
resolve_address_test: $(BINDIR)/$(CONFIG)/resolve_address_test
+resource_quota_test: $(BINDIR)/$(CONFIG)/resource_quota_test
secure_channel_create_test: $(BINDIR)/$(CONFIG)/secure_channel_create_test
secure_endpoint_test: $(BINDIR)/$(CONFIG)/secure_endpoint_test
sequential_connectivity_test: $(BINDIR)/$(CONFIG)/sequential_connectivity_test
@@ -1331,6 +1332,7 @@ buildtests_c: privatelibs_c \
$(BINDIR)/$(CONFIG)/murmur_hash_test \
$(BINDIR)/$(CONFIG)/no_server_test \
$(BINDIR)/$(CONFIG)/resolve_address_test \
+ $(BINDIR)/$(CONFIG)/resource_quota_test \
$(BINDIR)/$(CONFIG)/secure_channel_create_test \
$(BINDIR)/$(CONFIG)/secure_endpoint_test \
$(BINDIR)/$(CONFIG)/sequential_connectivity_test \
@@ -1717,6 +1719,8 @@ test_c: buildtests_c
$(Q) $(BINDIR)/$(CONFIG)/no_server_test || ( echo test no_server_test failed ; exit 1 )
$(E) "[RUN] Testing resolve_address_test"
$(Q) $(BINDIR)/$(CONFIG)/resolve_address_test || ( echo test resolve_address_test failed ; exit 1 )
+ $(E) "[RUN] Testing resource_quota_test"
+ $(Q) $(BINDIR)/$(CONFIG)/resource_quota_test || ( echo test resource_quota_test failed ; exit 1 )
$(E) "[RUN] Testing secure_channel_create_test"
$(Q) $(BINDIR)/$(CONFIG)/secure_channel_create_test || ( echo test secure_channel_create_test failed ; exit 1 )
$(E) "[RUN] Testing secure_endpoint_test"
@@ -2619,6 +2623,7 @@ LIBGRPC_SRC = \
src/core/lib/iomgr/resolve_address_posix.c \
src/core/lib/iomgr/resolve_address_uv.c \
src/core/lib/iomgr/resolve_address_windows.c \
+ src/core/lib/iomgr/resource_quota.c \
src/core/lib/iomgr/sockaddr_utils.c \
src/core/lib/iomgr/socket_utils_common_posix.c \
src/core/lib/iomgr/socket_utils_linux.c \
@@ -2908,6 +2913,7 @@ LIBGRPC_CRONET_SRC = \
src/core/lib/iomgr/resolve_address_posix.c \
src/core/lib/iomgr/resolve_address_uv.c \
src/core/lib/iomgr/resolve_address_windows.c \
+ src/core/lib/iomgr/resource_quota.c \
src/core/lib/iomgr/sockaddr_utils.c \
src/core/lib/iomgr/socket_utils_common_posix.c \
src/core/lib/iomgr/socket_utils_linux.c \
@@ -3188,6 +3194,7 @@ LIBGRPC_TEST_UTIL_SRC = \
src/core/lib/iomgr/resolve_address_posix.c \
src/core/lib/iomgr/resolve_address_uv.c \
src/core/lib/iomgr/resolve_address_windows.c \
+ src/core/lib/iomgr/resource_quota.c \
src/core/lib/iomgr/sockaddr_utils.c \
src/core/lib/iomgr/socket_utils_common_posix.c \
src/core/lib/iomgr/socket_utils_linux.c \
@@ -3397,6 +3404,7 @@ LIBGRPC_UNSECURE_SRC = \
src/core/lib/iomgr/resolve_address_posix.c \
src/core/lib/iomgr/resolve_address_uv.c \
src/core/lib/iomgr/resolve_address_windows.c \
+ src/core/lib/iomgr/resource_quota.c \
src/core/lib/iomgr/sockaddr_utils.c \
src/core/lib/iomgr/socket_utils_common_posix.c \
src/core/lib/iomgr/socket_utils_linux.c \
@@ -3693,6 +3701,7 @@ LIBGRPC++_SRC = \
src/cpp/common/channel_filter.cc \
src/cpp/common/completion_queue_cc.cc \
src/cpp/common/core_codegen.cc \
+ src/cpp/common/resource_quota_cc.cc \
src/cpp/common/rpc_method.cc \
src/cpp/server/async_generic_service.cc \
src/cpp/server/create_default_thread_pool.cc \
@@ -3737,6 +3746,7 @@ PUBLIC_HEADERS_CXX += \
include/grpc++/impl/thd.h \
include/grpc++/impl/thd_cxx11.h \
include/grpc++/impl/thd_no_cxx11.h \
+ include/grpc++/resource_quota.h \
include/grpc++/security/auth_context.h \
include/grpc++/security/auth_metadata_processor.h \
include/grpc++/security/credentials.h \
@@ -3885,6 +3895,7 @@ LIBGRPC++_CRONET_SRC = \
src/cpp/common/channel_filter.cc \
src/cpp/common/completion_queue_cc.cc \
src/cpp/common/core_codegen.cc \
+ src/cpp/common/resource_quota_cc.cc \
src/cpp/common/rpc_method.cc \
src/cpp/server/async_generic_service.cc \
src/cpp/server/create_default_thread_pool.cc \
@@ -3929,6 +3940,7 @@ PUBLIC_HEADERS_CXX += \
include/grpc++/impl/thd.h \
include/grpc++/impl/thd_cxx11.h \
include/grpc++/impl/thd_no_cxx11.h \
+ include/grpc++/resource_quota.h \
include/grpc++/security/auth_context.h \
include/grpc++/security/auth_metadata_processor.h \
include/grpc++/security/credentials.h \
@@ -4464,6 +4476,7 @@ LIBGRPC++_UNSECURE_SRC = \
src/cpp/common/channel_filter.cc \
src/cpp/common/completion_queue_cc.cc \
src/cpp/common/core_codegen.cc \
+ src/cpp/common/resource_quota_cc.cc \
src/cpp/common/rpc_method.cc \
src/cpp/server/async_generic_service.cc \
src/cpp/server/create_default_thread_pool.cc \
@@ -4508,6 +4521,7 @@ PUBLIC_HEADERS_CXX += \
include/grpc++/impl/thd.h \
include/grpc++/impl/thd_cxx11.h \
include/grpc++/impl/thd_no_cxx11.h \
+ include/grpc++/resource_quota.h \
include/grpc++/security/auth_context.h \
include/grpc++/security/auth_metadata_processor.h \
include/grpc++/security/credentials.h \
@@ -6942,6 +6956,7 @@ LIBEND2END_TESTS_SRC = \
test/core/end2end/tests/registered_call.c \
test/core/end2end/tests/request_with_flags.c \
test/core/end2end/tests/request_with_payload.c \
+ test/core/end2end/tests/resource_quota_server.c \
test/core/end2end/tests/server_finishes_request.c \
test/core/end2end/tests/shutdown_finishes_calls.c \
test/core/end2end/tests/shutdown_finishes_tags.c \
@@ -7024,6 +7039,7 @@ LIBEND2END_NOSEC_TESTS_SRC = \
test/core/end2end/tests/registered_call.c \
test/core/end2end/tests/request_with_flags.c \
test/core/end2end/tests/request_with_payload.c \
+ test/core/end2end/tests/resource_quota_server.c \
test/core/end2end/tests/server_finishes_request.c \
test/core/end2end/tests/shutdown_finishes_calls.c \
test/core/end2end/tests/shutdown_finishes_tags.c \
@@ -10420,6 +10436,38 @@ endif
endif
+RESOURCE_QUOTA_TEST_SRC = \
+ test/core/iomgr/resource_quota_test.c \
+
+RESOURCE_QUOTA_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(RESOURCE_QUOTA_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/resource_quota_test: openssl_dep_error
+
+else
+
+
+
+$(BINDIR)/$(CONFIG)/resource_quota_test: $(RESOURCE_QUOTA_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+ $(E) "[LD] Linking $@"
+ $(Q) mkdir -p `dirname $@`
+ $(Q) $(LD) $(LDFLAGS) $(RESOURCE_QUOTA_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/resource_quota_test
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/iomgr/resource_quota_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_resource_quota_test: $(RESOURCE_QUOTA_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(RESOURCE_QUOTA_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
SECURE_CHANNEL_CREATE_TEST_SRC = \
test/core/surface/secure_channel_create_test.c \
diff --git a/binding.gyp b/binding.gyp
index 23628f819b..9f3b75aaf3 100644
--- a/binding.gyp
+++ b/binding.gyp
@@ -612,6 +612,7 @@
'src/core/lib/iomgr/resolve_address_posix.c',
'src/core/lib/iomgr/resolve_address_uv.c',
'src/core/lib/iomgr/resolve_address_windows.c',
+ 'src/core/lib/iomgr/resource_quota.c',
'src/core/lib/iomgr/sockaddr_utils.c',
'src/core/lib/iomgr/socket_utils_common_posix.c',
'src/core/lib/iomgr/socket_utils_linux.c',
diff --git a/build.yaml b/build.yaml
index ed42dcd6a1..b5856d477b 100644
--- a/build.yaml
+++ b/build.yaml
@@ -208,6 +208,7 @@ filegroups:
- 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
@@ -216,6 +217,7 @@ filegroups:
- src/core/lib/iomgr/socket_utils_posix.h
- src/core/lib/iomgr/socket_windows.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_uv.h
@@ -303,6 +305,7 @@ filegroups:
- src/core/lib/iomgr/resolve_address_posix.c
- src/core/lib/iomgr/resolve_address_uv.c
- src/core/lib/iomgr/resolve_address_windows.c
+ - src/core/lib/iomgr/resource_quota.c
- src/core/lib/iomgr/sockaddr_utils.c
- src/core/lib/iomgr/socket_utils_common_posix.c
- src/core/lib/iomgr/socket_utils_linux.c
@@ -713,6 +716,7 @@ filegroups:
- include/grpc++/impl/thd.h
- include/grpc++/impl/thd_cxx11.h
- include/grpc++/impl/thd_no_cxx11.h
+ - include/grpc++/resource_quota.h
- include/grpc++/security/auth_context.h
- include/grpc++/security/auth_metadata_processor.h
- include/grpc++/security/credentials.h
@@ -750,6 +754,7 @@ filegroups:
- src/cpp/common/channel_filter.cc
- src/cpp/common/completion_queue_cc.cc
- src/cpp/common/core_codegen.cc
+ - src/cpp/common/resource_quota_cc.cc
- src/cpp/common/rpc_method.cc
- src/cpp/server/async_generic_service.cc
- src/cpp/server/create_default_thread_pool.cc
@@ -2427,6 +2432,17 @@ targets:
- gpr
exclude_iomgrs:
- uv
+- name: resource_quota_test
+ cpu_cost: 30
+ build: test
+ language: c
+ src:
+ - test/core/iomgr/resource_quota_test.c
+ deps:
+ - grpc_test_util
+ - grpc
+ - gpr_test_util
+ - gpr
- name: secure_channel_create_test
build: test
language: c
diff --git a/config.m4 b/config.m4
index 84af6bd3d0..8f26e42678 100644
--- a/config.m4
+++ b/config.m4
@@ -128,6 +128,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/iomgr/resolve_address_posix.c \
src/core/lib/iomgr/resolve_address_uv.c \
src/core/lib/iomgr/resolve_address_windows.c \
+ src/core/lib/iomgr/resource_quota.c \
src/core/lib/iomgr/sockaddr_utils.c \
src/core/lib/iomgr/socket_utils_common_posix.c \
src/core/lib/iomgr/socket_utils_linux.c \
diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec
index 0e4af8ae6c..75d79e3066 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -291,6 +291,7 @@ Pod::Spec.new do |s|
'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',
@@ -299,6 +300,7 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/socket_utils_posix.h',
'src/core/lib/iomgr/socket_windows.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_uv.h',
@@ -466,6 +468,7 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/resolve_address_posix.c',
'src/core/lib/iomgr/resolve_address_uv.c',
'src/core/lib/iomgr/resolve_address_windows.c',
+ 'src/core/lib/iomgr/resource_quota.c',
'src/core/lib/iomgr/sockaddr_utils.c',
'src/core/lib/iomgr/socket_utils_common_posix.c',
'src/core/lib/iomgr/socket_utils_linux.c',
@@ -684,6 +687,7 @@ Pod::Spec.new do |s|
'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',
@@ -692,6 +696,7 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/socket_utils_posix.h',
'src/core/lib/iomgr/socket_windows.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_uv.h',
diff --git a/grpc.def b/grpc.def
index 6e905a297e..0b6db801d8 100644
--- a/grpc.def
+++ b/grpc.def
@@ -94,6 +94,11 @@ EXPORTS
grpc_header_nonbin_value_is_legal
grpc_is_binary_header
grpc_call_error_to_string
+ grpc_resource_quota_create
+ grpc_resource_quota_ref
+ grpc_resource_quota_unref
+ grpc_resource_quota_resize
+ grpc_resource_quota_arg_vtable
grpc_insecure_channel_create_from_fd
grpc_server_add_insecure_channel_from_fd
grpc_use_signal
diff --git a/grpc.gemspec b/grpc.gemspec
index c5bb926cb5..615a962cdb 100755
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -211,6 +211,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/iomgr/pollset_windows.h )
s.files += %w( src/core/lib/iomgr/port.h )
s.files += %w( src/core/lib/iomgr/resolve_address.h )
+ s.files += %w( src/core/lib/iomgr/resource_quota.h )
s.files += %w( src/core/lib/iomgr/sockaddr.h )
s.files += %w( src/core/lib/iomgr/sockaddr_posix.h )
s.files += %w( src/core/lib/iomgr/sockaddr_utils.h )
@@ -219,6 +220,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/iomgr/socket_utils_posix.h )
s.files += %w( src/core/lib/iomgr/socket_windows.h )
s.files += %w( src/core/lib/iomgr/tcp_client.h )
+ s.files += %w( src/core/lib/iomgr/tcp_client_posix.h )
s.files += %w( src/core/lib/iomgr/tcp_posix.h )
s.files += %w( src/core/lib/iomgr/tcp_server.h )
s.files += %w( src/core/lib/iomgr/tcp_uv.h )
@@ -386,6 +388,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/iomgr/resolve_address_posix.c )
s.files += %w( src/core/lib/iomgr/resolve_address_uv.c )
s.files += %w( src/core/lib/iomgr/resolve_address_windows.c )
+ s.files += %w( src/core/lib/iomgr/resource_quota.c )
s.files += %w( src/core/lib/iomgr/sockaddr_utils.c )
s.files += %w( src/core/lib/iomgr/socket_utils_common_posix.c )
s.files += %w( src/core/lib/iomgr/socket_utils_linux.c )
diff --git a/include/grpc++/resource_quota.h b/include/grpc++/resource_quota.h
new file mode 100644
index 0000000000..db5bc8e7be
--- /dev/null
+++ b/include/grpc++/resource_quota.h
@@ -0,0 +1,70 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPCXX_RESOURCE_QUOTA_H
+#define GRPCXX_RESOURCE_QUOTA_H
+
+struct grpc_resource_quota;
+
+#include <grpc++/impl/codegen/config.h>
+
+namespace grpc {
+
+/// ResourceQuota represents a bound on memory usage by the gRPC library.
+/// A ResourceQuota can be attached to a server (via ServerBuilder), or a client
+/// channel (via ChannelArguments). gRPC will attempt to keep memory used by
+/// all attached entities below the ResourceQuota bound.
+class ResourceQuota GRPC_FINAL {
+ public:
+ explicit ResourceQuota(const grpc::string& name);
+ ResourceQuota();
+ ~ResourceQuota();
+
+ /// Resize this ResourceQuota to a new size. If new_size is smaller than the
+ /// current size of the pool, memory usage will be monotonically decreased
+ /// until it falls under new_size. No time bound is given for this to occur
+ /// however.
+ ResourceQuota& Resize(size_t new_size);
+
+ grpc_resource_quota* c_resource_quota() const { return impl_; }
+
+ private:
+ ResourceQuota(const ResourceQuota& rhs);
+ ResourceQuota& operator=(const ResourceQuota& rhs);
+
+ grpc_resource_quota* const impl_;
+};
+
+} // namespace grpc
+
+#endif // GRPCXX_RESOURCE_QUOTA_H
diff --git a/include/grpc++/server_builder.h b/include/grpc++/server_builder.h
index 37f1f8cb80..15333df60e 100644
--- a/include/grpc++/server_builder.h
+++ b/include/grpc++/server_builder.h
@@ -43,9 +43,12 @@
#include <grpc++/support/config.h>
#include <grpc/compression.h>
+struct grpc_resource_quota;
+
namespace grpc {
class AsyncGenericService;
+class ResourceQuota;
class CompletionQueue;
class RpcService;
class Server;
@@ -61,6 +64,7 @@ class ServerBuilderPluginTest;
class ServerBuilder {
public:
ServerBuilder();
+ ~ServerBuilder();
/// Register a service. This call does not take ownership of the service.
/// The service must exist for the lifetime of the \a Server instance returned
@@ -113,6 +117,9 @@ class ServerBuilder {
ServerBuilder& SetDefaultCompressionAlgorithm(
grpc_compression_algorithm algorithm);
+ /// Set the attached buffer pool for this server
+ ServerBuilder& SetResourceQuota(const ResourceQuota& resource_quota);
+
ServerBuilder& SetOption(std::unique_ptr<ServerBuilderOption> option);
/// Tries to bind \a server to the given \a addr.
@@ -187,6 +194,7 @@ class ServerBuilder {
std::vector<ServerCompletionQueue*> cqs_;
std::shared_ptr<ServerCredentials> creds_;
std::vector<std::unique_ptr<ServerBuilderPlugin>> plugins_;
+ grpc_resource_quota* resource_quota_;
AsyncGenericService* generic_service_;
struct {
bool is_set;
diff --git a/include/grpc++/support/channel_arguments.h b/include/grpc++/support/channel_arguments.h
index ae243939e9..ba203f85bd 100644
--- a/include/grpc++/support/channel_arguments.h
+++ b/include/grpc++/support/channel_arguments.h
@@ -46,6 +46,8 @@ namespace testing {
class ChannelArgumentsTest;
} // namespace testing
+class ResourceQuota;
+
/// Options for channel creation. The user can use generic setters to pass
/// key value pairs down to c channel creation code. For grpc related options,
/// concrete setters are provided.
@@ -80,6 +82,9 @@ class ChannelArguments {
/// The given string will be sent at the front of the user agent string.
void SetUserAgentPrefix(const grpc::string& user_agent_prefix);
+ /// The given buffer pool will be attached to the constructed channel
+ void SetResourceQuota(const ResourceQuota& resource_quota);
+
// Generic channel argument setters. Only for advanced use cases.
/// Set an integer argument \a value under \a key.
void SetInt(const grpc::string& key, int value);
@@ -88,6 +93,9 @@ class ChannelArguments {
/// Set a pointer argument \a value under \a key. Owership is not transferred.
void SetPointer(const grpc::string& key, void* value);
+ void SetPointerWithVtable(const grpc::string& key, void* value,
+ const grpc_arg_pointer_vtable* vtable);
+
/// Set a textual argument \a value under \a key.
void SetString(const grpc::string& key, const grpc::string& value);
diff --git a/include/grpc/grpc.h b/include/grpc/grpc.h
index 587d86c98f..f8e442274e 100644
--- a/include/grpc/grpc.h
+++ b/include/grpc/grpc.h
@@ -401,6 +401,23 @@ GRPCAPI int grpc_is_binary_header(const char *key, size_t length);
/** Convert grpc_call_error values to a string */
GRPCAPI const char *grpc_call_error_to_string(grpc_call_error error);
+/** Create a buffer pool */
+GRPCAPI grpc_resource_quota *grpc_resource_quota_create(const char *trace_name);
+
+/** Add a reference to a buffer pool */
+GRPCAPI void grpc_resource_quota_ref(grpc_resource_quota *resource_quota);
+
+/** Drop a reference to a buffer pool */
+GRPCAPI void grpc_resource_quota_unref(grpc_resource_quota *resource_quota);
+
+/** Update the size of a buffer pool */
+GRPCAPI void grpc_resource_quota_resize(grpc_resource_quota *resource_quota,
+ size_t new_size);
+
+/** Fetch a vtable for a grpc_channel_arg that points to a grpc_resource_quota
+ */
+GRPCAPI const grpc_arg_pointer_vtable *grpc_resource_quota_arg_vtable(void);
+
#ifdef __cplusplus
}
#endif
diff --git a/include/grpc/impl/codegen/grpc_types.h b/include/grpc/impl/codegen/grpc_types.h
index 0be7ab2ad2..66ece3c8a0 100644
--- a/include/grpc/impl/codegen/grpc_types.h
+++ b/include/grpc/impl/codegen/grpc_types.h
@@ -201,6 +201,9 @@ typedef struct {
#define GRPC_ARG_MAX_METADATA_SIZE "grpc.max_metadata_size"
/** If non-zero, allow the use of SO_REUSEPORT if it's available (default 1) */
#define GRPC_ARG_ALLOW_REUSEPORT "grpc.so_reuseport"
+/** If non-zero, a pointer to a buffer pool (use grpc_resource_quota_arg_vtable
+ to fetch an appropriate pointer arg vtable */
+#define GRPC_ARG_RESOURCE_QUOTA "grpc.resource_quota"
/** Service config data, to be passed to subchannels.
Not intended for external use. */
#define GRPC_ARG_SERVICE_CONFIG "grpc.service_config"
@@ -467,6 +470,8 @@ typedef struct grpc_op {
} data;
} grpc_op;
+typedef struct grpc_resource_quota grpc_resource_quota;
+
#ifdef __cplusplus
}
#endif
diff --git a/package.xml b/package.xml
index d4a4e3c7b9..a60eac6820 100644
--- a/package.xml
+++ b/package.xml
@@ -218,6 +218,7 @@
<file baseinstalldir="/" name="src/core/lib/iomgr/pollset_windows.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/port.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/resolve_address.h" role="src" />
+ <file baseinstalldir="/" name="src/core/lib/iomgr/resource_quota.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/sockaddr.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/sockaddr_posix.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/sockaddr_utils.h" role="src" />
@@ -226,6 +227,7 @@
<file baseinstalldir="/" name="src/core/lib/iomgr/socket_utils_posix.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/socket_windows.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/tcp_client.h" role="src" />
+ <file baseinstalldir="/" name="src/core/lib/iomgr/tcp_client_posix.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/tcp_posix.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/tcp_server.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/tcp_uv.h" role="src" />
@@ -393,6 +395,7 @@
<file baseinstalldir="/" name="src/core/lib/iomgr/resolve_address_posix.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/resolve_address_uv.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/resolve_address_windows.c" role="src" />
+ <file baseinstalldir="/" name="src/core/lib/iomgr/resource_quota.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/sockaddr_utils.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/socket_utils_common_posix.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/socket_utils_linux.c" role="src" />
diff --git a/src/core/ext/client_channel/client_channel.c b/src/core/ext/client_channel/client_channel.c
index 80b4f048c2..ff773ac334 100644
--- a/src/core/ext/client_channel/client_channel.c
+++ b/src/core/ext/client_channel/client_channel.c
@@ -1022,6 +1022,10 @@ static void cc_destroy_call_elem(grpc_exec_ctx *exec_ctx,
GPR_ASSERT(calld->creation_phase == GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING);
gpr_mu_destroy(&calld->mu);
GPR_ASSERT(calld->waiting_ops_count == 0);
+ if (calld->connected_subchannel != NULL) {
+ GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, calld->connected_subchannel,
+ "picked");
+ }
gpr_free(calld->waiting_ops);
gpr_free(and_free_memory);
}
diff --git a/src/core/ext/client_channel/subchannel.c b/src/core/ext/client_channel/subchannel.c
index ab6aede23a..789966cb69 100644
--- a/src/core/ext/client_channel/subchannel.c
+++ b/src/core/ext/client_channel/subchannel.c
@@ -183,9 +183,10 @@ static void connection_destroy(grpc_exec_ctx *exec_ctx, void *arg,
gpr_free(c);
}
-void grpc_connected_subchannel_ref(
+grpc_connected_subchannel *grpc_connected_subchannel_ref(
grpc_connected_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
GRPC_CHANNEL_STACK_REF(CHANNEL_STACK_FROM_CONNECTION(c), REF_REASON);
+ return c;
}
void grpc_connected_subchannel_unref(grpc_exec_ctx *exec_ctx,
diff --git a/src/core/ext/client_channel/subchannel.h b/src/core/ext/client_channel/subchannel.h
index 5652074074..93bd72d20d 100644
--- a/src/core/ext/client_channel/subchannel.h
+++ b/src/core/ext/client_channel/subchannel.h
@@ -97,7 +97,7 @@ grpc_subchannel *grpc_subchannel_weak_ref(
void grpc_subchannel_weak_unref(grpc_exec_ctx *exec_ctx,
grpc_subchannel *channel
GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
-void grpc_connected_subchannel_ref(
+grpc_connected_subchannel *grpc_connected_subchannel_ref(
grpc_connected_subchannel *channel GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
void grpc_connected_subchannel_unref(grpc_exec_ctx *exec_ctx,
grpc_connected_subchannel *channel
diff --git a/src/core/ext/lb_policy/pick_first/pick_first.c b/src/core/ext/lb_policy/pick_first/pick_first.c
index 5d3433df74..ac3c6a305a 100644
--- a/src/core/ext/lb_policy/pick_first/pick_first.c
+++ b/src/core/ext/lb_policy/pick_first/pick_first.c
@@ -209,7 +209,7 @@ static int pf_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
/* Check atomically for a selected channel */
grpc_connected_subchannel *selected = GET_SELECTED(p);
if (selected != NULL) {
- *target = selected;
+ *target = GRPC_CONNECTED_SUBCHANNEL_REF(selected, "picked");
return 1;
}
@@ -218,7 +218,7 @@ static int pf_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
selected = GET_SELECTED(p);
if (selected) {
gpr_mu_unlock(&p->mu);
- *target = selected;
+ *target = GRPC_CONNECTED_SUBCHANNEL_REF(selected, "picked");
return 1;
} else {
if (!p->started_picking) {
@@ -310,7 +310,7 @@ static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
/* update any calls that were waiting for a pick */
while ((pp = p->pending_picks)) {
p->pending_picks = pp->next;
- *pp->target = selected;
+ *pp->target = GRPC_CONNECTED_SUBCHANNEL_REF(selected, "picked");
grpc_exec_ctx_sched(exec_ctx, pp->on_complete, GRPC_ERROR_NONE, NULL);
gpr_free(pp);
}
diff --git a/src/core/ext/lb_policy/round_robin/round_robin.c b/src/core/ext/lb_policy/round_robin/round_robin.c
index c0743b00e8..37a9b18b97 100644
--- a/src/core/ext/lb_policy/round_robin/round_robin.c
+++ b/src/core/ext/lb_policy/round_robin/round_robin.c
@@ -397,7 +397,9 @@ static int rr_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
gpr_mu_lock(&p->mu);
if ((selected = peek_next_connected_locked(p))) {
/* readily available, report right away */
- *target = grpc_subchannel_get_connected_subchannel(selected->subchannel);
+ *target = GRPC_CONNECTED_SUBCHANNEL_REF(
+ grpc_subchannel_get_connected_subchannel(selected->subchannel),
+ "picked");
if (user_data != NULL) {
*user_data = selected->user_data;
@@ -463,8 +465,9 @@ static void rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
while ((pp = p->pending_picks)) {
p->pending_picks = pp->next;
- *pp->target =
- grpc_subchannel_get_connected_subchannel(selected->subchannel);
+ *pp->target = GRPC_CONNECTED_SUBCHANNEL_REF(
+ grpc_subchannel_get_connected_subchannel(selected->subchannel),
+ "picked");
if (pp->user_data != NULL) {
*pp->user_data = selected->user_data;
}
@@ -578,7 +581,9 @@ static void rr_ping_one(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
gpr_mu_lock(&p->mu);
if ((selected = peek_next_connected_locked(p))) {
gpr_mu_unlock(&p->mu);
- target = grpc_subchannel_get_connected_subchannel(selected->subchannel);
+ target = GRPC_CONNECTED_SUBCHANNEL_REF(
+ grpc_subchannel_get_connected_subchannel(selected->subchannel),
+ "picked");
grpc_connected_subchannel_ping(exec_ctx, target, closure);
} else {
gpr_mu_unlock(&p->mu);
diff --git a/src/core/ext/transport/chttp2/client/insecure/channel_create.c b/src/core/ext/transport/chttp2/client/insecure/channel_create.c
index 372fb7bf4c..71a06e118b 100644
--- a/src/core/ext/transport/chttp2/client/insecure/channel_create.c
+++ b/src/core/ext/transport/chttp2/client/insecure/channel_create.c
@@ -154,7 +154,8 @@ static void connector_connect(grpc_exec_ctx *exec_ctx, grpc_connector *con,
c->tcp = NULL;
grpc_closure_init(&c->connected, connected, c);
grpc_tcp_client_connect(exec_ctx, &c->connected, &c->tcp,
- args->interested_parties, args->addr, args->deadline);
+ args->interested_parties, args->channel_args,
+ args->addr, args->deadline);
}
static const grpc_connector_vtable connector_vtable = {
diff --git a/src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c b/src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c
index b2c5e5b088..1e5b1c22e3 100644
--- a/src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c
+++ b/src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c
@@ -44,6 +44,7 @@
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/iomgr/endpoint.h"
#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/iomgr/tcp_client_posix.h"
#include "src/core/lib/iomgr/tcp_posix.h"
#include "src/core/lib/surface/api_trace.h"
#include "src/core/lib/surface/channel.h"
@@ -65,9 +66,8 @@ grpc_channel *grpc_insecure_channel_create_from_fd(
int flags = fcntl(fd, F_GETFL, 0);
GPR_ASSERT(fcntl(fd, F_SETFL, flags | O_NONBLOCK) == 0);
- grpc_endpoint *client =
- grpc_tcp_create(grpc_fd_create(fd, "client"),
- GRPC_TCP_DEFAULT_READ_SLICE_SIZE, "fd-client");
+ grpc_endpoint *client = grpc_tcp_client_create_from_fd(
+ &exec_ctx, grpc_fd_create(fd, "client"), args, "fd-client");
grpc_transport *transport =
grpc_create_chttp2_transport(&exec_ctx, final_args, client, 1);
diff --git a/src/core/ext/transport/chttp2/client/secure/secure_channel_create.c b/src/core/ext/transport/chttp2/client/secure/secure_channel_create.c
index 29095af207..57e1a8ec01 100644
--- a/src/core/ext/transport/chttp2/client/secure/secure_channel_create.c
+++ b/src/core/ext/transport/chttp2/client/secure/secure_channel_create.c
@@ -212,9 +212,9 @@ static void connector_connect(grpc_exec_ctx *exec_ctx, grpc_connector *con,
GPR_ASSERT(c->connecting_endpoint == NULL);
gpr_mu_unlock(&c->mu);
grpc_closure_init(&c->connected_closure, connected, c);
- grpc_tcp_client_connect(exec_ctx, &c->connected_closure,
- &c->newly_connecting_endpoint,
- args->interested_parties, args->addr, args->deadline);
+ grpc_tcp_client_connect(
+ exec_ctx, &c->connected_closure, &c->newly_connecting_endpoint,
+ args->interested_parties, args->channel_args, args->addr, args->deadline);
}
static const grpc_connector_vtable connector_vtable = {
diff --git a/src/core/ext/transport/chttp2/server/insecure/server_chttp2.c b/src/core/ext/transport/chttp2/server/insecure/server_chttp2.c
index e4967c2f08..d42611b863 100644
--- a/src/core/ext/transport/chttp2/server/insecure/server_chttp2.c
+++ b/src/core/ext/transport/chttp2/server/insecure/server_chttp2.c
@@ -139,8 +139,8 @@ int grpc_server_add_insecure_http2_port(grpc_server *server, const char *addr) {
goto error;
}
- err =
- grpc_tcp_server_create(NULL, grpc_server_get_channel_args(server), &tcp);
+ err = grpc_tcp_server_create(&exec_ctx, NULL,
+ grpc_server_get_channel_args(server), &tcp);
if (err != GRPC_ERROR_NONE) {
goto error;
}
diff --git a/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c b/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c
index 9af17fb5ae..aa2ecf5743 100644
--- a/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c
+++ b/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c
@@ -57,8 +57,12 @@ void grpc_server_add_insecure_channel_from_fd(grpc_server *server,
char *name;
gpr_asprintf(&name, "fd:%d", fd);
- grpc_endpoint *server_endpoint = grpc_tcp_create(
- grpc_fd_create(fd, name), GRPC_TCP_DEFAULT_READ_SLICE_SIZE, name);
+ grpc_resource_quota *resource_quota = grpc_resource_quota_from_channel_args(
+ grpc_server_get_channel_args(server));
+ grpc_endpoint *server_endpoint =
+ grpc_tcp_create(grpc_fd_create(fd, name), resource_quota,
+ GRPC_TCP_DEFAULT_READ_SLICE_SIZE, name);
+ grpc_resource_quota_internal_unref(&exec_ctx, resource_quota);
gpr_free(name);
diff --git a/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c b/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c
index 0fab888541..7ad687042d 100644
--- a/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c
+++ b/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c
@@ -271,7 +271,8 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
memset(server_state, 0, sizeof(*server_state));
grpc_closure_init(&server_state->tcp_server_shutdown_complete,
tcp_server_shutdown_complete, server_state);
- err = grpc_tcp_server_create(&server_state->tcp_server_shutdown_complete,
+ err = grpc_tcp_server_create(&exec_ctx,
+ &server_state->tcp_server_shutdown_complete,
grpc_server_get_channel_args(server), &tcp);
if (err != GRPC_ERROR_NONE) {
goto error;
diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
index ecf3aea870..4a9f806354 100644
--- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c
+++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
@@ -114,6 +114,20 @@ static void fail_pending_writes(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t, grpc_chttp2_stream *s,
grpc_error *error);
+static void benign_reclaimer(grpc_exec_ctx *exec_ctx, void *t,
+ grpc_error *error);
+static void benign_reclaimer_locked(grpc_exec_ctx *exec_ctx, void *t,
+ grpc_error *error);
+static void destructive_reclaimer(grpc_exec_ctx *exec_ctx, void *t,
+ grpc_error *error);
+static void destructive_reclaimer_locked(grpc_exec_ctx *exec_ctx, void *t,
+ grpc_error *error);
+
+static void post_benign_reclaimer(grpc_exec_ctx *exec_ctx,
+ grpc_chttp2_transport *t);
+static void post_destructive_reclaimer(grpc_exec_ctx *exec_ctx,
+ grpc_chttp2_transport *t);
+
static void close_transport_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t, grpc_error *error);
static void end_all_the_calls(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
@@ -241,6 +255,11 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
grpc_closure_init(&t->write_action_end_locked, write_action_end_locked, t);
grpc_closure_init(&t->read_action_begin, read_action_begin, t);
grpc_closure_init(&t->read_action_locked, read_action_locked, t);
+ grpc_closure_init(&t->benign_reclaimer, benign_reclaimer, t);
+ grpc_closure_init(&t->destructive_reclaimer, destructive_reclaimer, t);
+ grpc_closure_init(&t->benign_reclaimer_locked, benign_reclaimer_locked, t);
+ grpc_closure_init(&t->destructive_reclaimer_locked,
+ destructive_reclaimer_locked, t);
grpc_chttp2_goaway_parser_init(&t->goaway_parser);
grpc_chttp2_hpack_parser_init(&t->hpack_parser);
@@ -362,6 +381,7 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
}
grpc_chttp2_initiate_write(exec_ctx, t, false, "init");
+ post_benign_reclaimer(exec_ctx, t);
}
static void destroy_transport_locked(grpc_exec_ctx *exec_ctx, void *tp,
@@ -467,6 +487,7 @@ static int init_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
[GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
*t->accepting_stream = s;
grpc_chttp2_stream_map_add(&t->stream_map, s->id, s);
+ post_destructive_reclaimer(exec_ctx, t);
}
GPR_TIMER_END("init_stream", 0);
@@ -675,6 +696,13 @@ static void write_action_end_locked(grpc_exec_ctx *exec_ctx, void *tp,
close_transport_locked(exec_ctx, t, GRPC_ERROR_REF(error));
}
+ if (t->sent_goaway_state == GRPC_CHTTP2_GOAWAY_SEND_SCHEDULED) {
+ t->sent_goaway_state = GRPC_CHTTP2_GOAWAY_SENT;
+ if (grpc_chttp2_stream_map_size(&t->stream_map) == 0) {
+ close_transport_locked(exec_ctx, t, GRPC_ERROR_CREATE("goaway sent"));
+ }
+ }
+
grpc_chttp2_end_write(exec_ctx, t, GRPC_ERROR_REF(error));
switch (t->write_state) {
@@ -780,6 +808,7 @@ static void maybe_start_some_streams(grpc_exec_ctx *exec_ctx,
[GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
s->max_recv_bytes = GPR_MAX(stream_incoming_window, s->max_recv_bytes);
grpc_chttp2_stream_map_add(&t->stream_map, s->id, s);
+ post_destructive_reclaimer(exec_ctx, t);
grpc_chttp2_become_writable(exec_ctx, t, s, true, "new_stream");
}
/* cancel out streams that will never be started */
@@ -993,9 +1022,14 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op,
}
if (!s->write_closed) {
if (t->is_client) {
- GPR_ASSERT(s->id == 0);
- grpc_chttp2_list_add_waiting_for_concurrency(t, s);
- maybe_start_some_streams(exec_ctx, t);
+ if (!t->closed) {
+ GPR_ASSERT(s->id == 0);
+ grpc_chttp2_list_add_waiting_for_concurrency(t, s);
+ maybe_start_some_streams(exec_ctx, t);
+ } else {
+ grpc_chttp2_cancel_stream(exec_ctx, t, s,
+ GRPC_ERROR_CREATE("Transport closed"));
+ }
} else {
GPR_ASSERT(s->id != 0);
grpc_chttp2_become_writable(exec_ctx, t, s, true,
@@ -1185,6 +1219,14 @@ void grpc_chttp2_ack_ping(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
gpr_free(msg);
}
+static void send_goaway(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
+ grpc_chttp2_error_code error, gpr_slice data) {
+ t->sent_goaway_state = GRPC_CHTTP2_GOAWAY_SEND_SCHEDULED;
+ grpc_chttp2_goaway_append(t->last_new_stream_id, (uint32_t)error, data,
+ &t->qbuf);
+ grpc_chttp2_initiate_write(exec_ctx, t, false, "goaway_sent");
+}
+
static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx,
void *stream_op,
grpc_error *error_ignored) {
@@ -1199,15 +1241,9 @@ static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx,
}
if (op->send_goaway) {
- t->sent_goaway = 1;
- grpc_chttp2_goaway_append(
- t->last_new_stream_id,
- (uint32_t)grpc_chttp2_grpc_status_to_http2_error(op->goaway_status),
- gpr_slice_ref(*op->goaway_message), &t->qbuf);
- close_transport = grpc_chttp2_stream_map_size(&t->stream_map) == 0
- ? GRPC_ERROR_CREATE("GOAWAY sent")
- : GRPC_ERROR_NONE;
- grpc_chttp2_initiate_write(exec_ctx, t, false, "goaway_sent");
+ send_goaway(exec_ctx, t,
+ grpc_chttp2_grpc_status_to_http2_error(op->goaway_status),
+ gpr_slice_ref(*op->goaway_message));
}
if (op->set_accept_stream) {
@@ -1341,10 +1377,14 @@ static void remove_stream(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
s->data_parser.parsing_frame = NULL;
}
- if (grpc_chttp2_stream_map_size(&t->stream_map) == 0 && t->sent_goaway) {
- close_transport_locked(
- exec_ctx, t, GRPC_ERROR_CREATE_REFERENCING(
- "Last stream closed after sending GOAWAY", &error, 1));
+ if (grpc_chttp2_stream_map_size(&t->stream_map) == 0) {
+ post_benign_reclaimer(exec_ctx, t);
+ if (t->sent_goaway_state == GRPC_CHTTP2_GOAWAY_SENT) {
+ close_transport_locked(
+ exec_ctx, t,
+ GRPC_ERROR_CREATE_REFERENCING(
+ "Last stream closed after sending GOAWAY", &error, 1));
+ }
}
if (grpc_chttp2_list_remove_writable_stream(t, s)) {
GRPC_CHTTP2_STREAM_UNREF(exec_ctx, s, "chttp2_writing:remove_stream");
@@ -2072,6 +2112,103 @@ grpc_chttp2_incoming_byte_stream *grpc_chttp2_incoming_byte_stream_create(
}
/*******************************************************************************
+ * RESOURCE QUOTAS
+ */
+
+static void post_benign_reclaimer(grpc_exec_ctx *exec_ctx,
+ grpc_chttp2_transport *t) {
+ if (!t->benign_reclaimer_registered) {
+ t->benign_reclaimer_registered = true;
+ GRPC_CHTTP2_REF_TRANSPORT(t, "benign_reclaimer");
+ grpc_resource_user_post_reclaimer(exec_ctx,
+ grpc_endpoint_get_resource_user(t->ep),
+ false, &t->benign_reclaimer);
+ }
+}
+
+static void post_destructive_reclaimer(grpc_exec_ctx *exec_ctx,
+ grpc_chttp2_transport *t) {
+ if (!t->destructive_reclaimer_registered) {
+ t->destructive_reclaimer_registered = true;
+ GRPC_CHTTP2_REF_TRANSPORT(t, "destructive_reclaimer");
+ grpc_resource_user_post_reclaimer(exec_ctx,
+ grpc_endpoint_get_resource_user(t->ep),
+ true, &t->destructive_reclaimer);
+ }
+}
+
+static void benign_reclaimer(grpc_exec_ctx *exec_ctx, void *arg,
+ grpc_error *error) {
+ grpc_chttp2_transport *t = arg;
+ grpc_combiner_execute(exec_ctx, t->combiner, &t->benign_reclaimer_locked,
+ GRPC_ERROR_REF(error), false);
+}
+
+static void destructive_reclaimer(grpc_exec_ctx *exec_ctx, void *arg,
+ grpc_error *error) {
+ grpc_chttp2_transport *t = arg;
+ grpc_combiner_execute(exec_ctx, t->combiner, &t->destructive_reclaimer_locked,
+ GRPC_ERROR_REF(error), false);
+}
+
+static void benign_reclaimer_locked(grpc_exec_ctx *exec_ctx, void *arg,
+ grpc_error *error) {
+ grpc_chttp2_transport *t = arg;
+ if (error == GRPC_ERROR_NONE &&
+ grpc_chttp2_stream_map_size(&t->stream_map) == 0) {
+ /* Channel with no active streams: send a goaway to try and make it
+ * disconnect cleanly */
+ if (grpc_resource_quota_trace) {
+ gpr_log(GPR_DEBUG, "HTTP2: %s - send goaway to free memory",
+ t->peer_string);
+ }
+ send_goaway(exec_ctx, t, GRPC_CHTTP2_ENHANCE_YOUR_CALM,
+ gpr_slice_from_static_string("Buffers full"));
+ } else if (error == GRPC_ERROR_NONE && grpc_resource_quota_trace) {
+ gpr_log(GPR_DEBUG,
+ "HTTP2: %s - skip benign reclamation, there are still %" PRIdPTR
+ " streams",
+ t->peer_string, grpc_chttp2_stream_map_size(&t->stream_map));
+ }
+ t->benign_reclaimer_registered = false;
+ if (error != GRPC_ERROR_CANCELLED) {
+ grpc_resource_user_finish_reclamation(
+ exec_ctx, grpc_endpoint_get_resource_user(t->ep));
+ }
+ GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "benign_reclaimer");
+}
+
+static void destructive_reclaimer_locked(grpc_exec_ctx *exec_ctx, void *arg,
+ grpc_error *error) {
+ grpc_chttp2_transport *t = arg;
+ size_t n = grpc_chttp2_stream_map_size(&t->stream_map);
+ t->destructive_reclaimer_registered = false;
+ if (error == GRPC_ERROR_NONE && n > 0) {
+ grpc_chttp2_stream *s = grpc_chttp2_stream_map_rand(&t->stream_map);
+ if (grpc_resource_quota_trace) {
+ gpr_log(GPR_DEBUG, "HTTP2: %s - abandon stream id %d", t->peer_string,
+ s->id);
+ }
+ grpc_chttp2_cancel_stream(
+ exec_ctx, t, s, grpc_error_set_int(GRPC_ERROR_CREATE("Buffers full"),
+ GRPC_ERROR_INT_HTTP2_ERROR,
+ GRPC_CHTTP2_ENHANCE_YOUR_CALM));
+ if (n > 1) {
+ /* Since we cancel one stream per destructive reclamation, if
+ there are more streams left, we can immediately post a new
+ reclaimer in case the resource quota needs to free more
+ memory */
+ post_destructive_reclaimer(exec_ctx, t);
+ }
+ }
+ if (error != GRPC_ERROR_CANCELLED) {
+ grpc_resource_user_finish_reclamation(
+ exec_ctx, grpc_endpoint_get_resource_user(t->ep));
+ }
+ GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "destructive_reclaimer");
+}
+
+/*******************************************************************************
* TRACING
*/
diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h
index 01f521c360..e0c4a1e925 100644
--- a/src/core/ext/transport/chttp2/transport/internal.h
+++ b/src/core/ext/transport/chttp2/transport/internal.h
@@ -138,6 +138,12 @@ typedef enum {
GRPC_NUM_SETTING_SETS
} grpc_chttp2_setting_set;
+typedef enum {
+ GRPC_CHTTP2_NO_GOAWAY_SEND,
+ GRPC_CHTTP2_GOAWAY_SEND_SCHEDULED,
+ GRPC_CHTTP2_GOAWAY_SENT,
+} grpc_chttp2_sent_goaway_state;
+
/* Outstanding ping request data */
typedef struct grpc_chttp2_outstanding_ping {
uint8_t id[8];
@@ -249,7 +255,7 @@ struct grpc_chttp2_transport {
/** have we seen a goaway */
uint8_t seen_goaway;
/** have we sent a goaway */
- uint8_t sent_goaway;
+ grpc_chttp2_sent_goaway_state sent_goaway_state;
/** are the local settings dirty and need to be sent? */
uint8_t dirtied_local_settings;
@@ -320,6 +326,18 @@ struct grpc_chttp2_transport {
/* if non-NULL, close the transport with this error when writes are finished
*/
grpc_error *close_transport_on_writes_finished;
+
+ /* buffer pool state */
+ /** have we scheduled a benign cleanup? */
+ bool benign_reclaimer_registered;
+ /** have we scheduled a destructive cleanup? */
+ bool destructive_reclaimer_registered;
+ /** benign cleanup closure */
+ grpc_closure benign_reclaimer;
+ grpc_closure benign_reclaimer_locked;
+ /** destructive cleanup closure */
+ grpc_closure destructive_reclaimer;
+ grpc_closure destructive_reclaimer_locked;
};
typedef enum {
diff --git a/src/core/ext/transport/chttp2/transport/stream_map.c b/src/core/ext/transport/chttp2/transport/stream_map.c
index 59b3a14e0a..5f5a28446d 100644
--- a/src/core/ext/transport/chttp2/transport/stream_map.c
+++ b/src/core/ext/transport/chttp2/transport/stream_map.c
@@ -151,6 +151,17 @@ size_t grpc_chttp2_stream_map_size(grpc_chttp2_stream_map *map) {
return map->count - map->free;
}
+void *grpc_chttp2_stream_map_rand(grpc_chttp2_stream_map *map) {
+ if (map->count == map->free) {
+ return NULL;
+ }
+ if (map->free != 0) {
+ map->count = compact(map->keys, map->values, map->count);
+ map->free = 0;
+ }
+ return map->values[((size_t)rand()) % map->count];
+}
+
void grpc_chttp2_stream_map_for_each(grpc_chttp2_stream_map *map,
void (*f)(void *user_data, uint32_t key,
void *value),
diff --git a/src/core/ext/transport/chttp2/transport/stream_map.h b/src/core/ext/transport/chttp2/transport/stream_map.h
index e76312dd1a..203f640680 100644
--- a/src/core/ext/transport/chttp2/transport/stream_map.h
+++ b/src/core/ext/transport/chttp2/transport/stream_map.h
@@ -68,6 +68,9 @@ void *grpc_chttp2_stream_map_delete(grpc_chttp2_stream_map *map, uint32_t key);
/* Return an existing key, or NULL if it does not exist */
void *grpc_chttp2_stream_map_find(grpc_chttp2_stream_map *map, uint32_t key);
+/* Return a random entry */
+void *grpc_chttp2_stream_map_rand(grpc_chttp2_stream_map *map);
+
/* How many (populated) entries are in the stream map? */
size_t grpc_chttp2_stream_map_size(grpc_chttp2_stream_map *map);
diff --git a/src/core/lib/http/httpcli.c b/src/core/lib/http/httpcli.c
index 55de1b5990..411e669b53 100644
--- a/src/core/lib/http/httpcli.c
+++ b/src/core/lib/http/httpcli.c
@@ -70,6 +70,7 @@ typedef struct {
grpc_closure done_write;
grpc_closure connected;
grpc_error *overall_error;
+ grpc_resource_quota *resource_quota;
} internal_request;
static grpc_httpcli_get_override g_get_override = NULL;
@@ -117,6 +118,7 @@ static void finish(grpc_exec_ctx *exec_ctx, internal_request *req,
gpr_slice_buffer_destroy(&req->incoming);
gpr_slice_buffer_destroy(&req->outgoing);
GRPC_ERROR_UNREF(req->overall_error);
+ grpc_resource_quota_internal_unref(exec_ctx, req->resource_quota);
gpr_free(req);
}
@@ -223,8 +225,15 @@ static void next_address(grpc_exec_ctx *exec_ctx, internal_request *req,
}
addr = &req->addresses->addrs[req->next_address++];
grpc_closure_init(&req->connected, on_connected, req);
+ grpc_arg arg;
+ arg.key = GRPC_ARG_RESOURCE_QUOTA;
+ arg.type = GRPC_ARG_POINTER;
+ arg.value.pointer.p = req->resource_quota;
+ arg.value.pointer.vtable = grpc_resource_quota_arg_vtable();
+ grpc_channel_args args = {1, &arg};
grpc_tcp_client_connect(exec_ctx, &req->connected, &req->ep,
- req->context->pollset_set, addr, req->deadline);
+ req->context->pollset_set, &args, addr,
+ req->deadline);
}
static void on_resolved(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
@@ -240,6 +249,7 @@ static void on_resolved(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
static void internal_request_begin(grpc_exec_ctx *exec_ctx,
grpc_httpcli_context *context,
grpc_polling_entity *pollent,
+ grpc_resource_quota *resource_quota,
const grpc_httpcli_request *request,
gpr_timespec deadline, grpc_closure *on_done,
grpc_httpcli_response *response,
@@ -255,6 +265,7 @@ static void internal_request_begin(grpc_exec_ctx *exec_ctx,
req->context = context;
req->pollent = pollent;
req->overall_error = GRPC_ERROR_NONE;
+ req->resource_quota = grpc_resource_quota_internal_ref(resource_quota);
grpc_closure_init(&req->on_read, on_read, req);
grpc_closure_init(&req->done_write, done_write, req);
gpr_slice_buffer_init(&req->incoming);
@@ -272,6 +283,7 @@ static void internal_request_begin(grpc_exec_ctx *exec_ctx,
void grpc_httpcli_get(grpc_exec_ctx *exec_ctx, grpc_httpcli_context *context,
grpc_polling_entity *pollent,
+ grpc_resource_quota *resource_quota,
const grpc_httpcli_request *request,
gpr_timespec deadline, grpc_closure *on_done,
grpc_httpcli_response *response) {
@@ -281,14 +293,15 @@ void grpc_httpcli_get(grpc_exec_ctx *exec_ctx, grpc_httpcli_context *context,
return;
}
gpr_asprintf(&name, "HTTP:GET:%s:%s", request->host, request->http.path);
- internal_request_begin(exec_ctx, context, pollent, request, deadline, on_done,
- response, name,
+ internal_request_begin(exec_ctx, context, pollent, resource_quota, request,
+ deadline, on_done, response, name,
grpc_httpcli_format_get_request(request));
gpr_free(name);
}
void grpc_httpcli_post(grpc_exec_ctx *exec_ctx, grpc_httpcli_context *context,
grpc_polling_entity *pollent,
+ grpc_resource_quota *resource_quota,
const grpc_httpcli_request *request,
const char *body_bytes, size_t body_size,
gpr_timespec deadline, grpc_closure *on_done,
@@ -301,7 +314,8 @@ void grpc_httpcli_post(grpc_exec_ctx *exec_ctx, grpc_httpcli_context *context,
}
gpr_asprintf(&name, "HTTP:POST:%s:%s", request->host, request->http.path);
internal_request_begin(
- exec_ctx, context, pollent, request, deadline, on_done, response, name,
+ exec_ctx, context, pollent, resource_quota, request, deadline, on_done,
+ response, name,
grpc_httpcli_format_post_request(request, body_bytes, body_size));
gpr_free(name);
}
diff --git a/src/core/lib/http/httpcli.h b/src/core/lib/http/httpcli.h
index 320c0f86c6..11e03b44df 100644
--- a/src/core/lib/http/httpcli.h
+++ b/src/core/lib/http/httpcli.h
@@ -96,6 +96,7 @@ void grpc_httpcli_context_destroy(grpc_httpcli_context *context);
'on_response' is a callback to report results to */
void grpc_httpcli_get(grpc_exec_ctx *exec_ctx, grpc_httpcli_context *context,
grpc_polling_entity *pollent,
+ grpc_resource_quota *resource_quota,
const grpc_httpcli_request *request,
gpr_timespec deadline, grpc_closure *on_complete,
grpc_httpcli_response *response);
@@ -116,6 +117,7 @@ void grpc_httpcli_get(grpc_exec_ctx *exec_ctx, grpc_httpcli_context *context,
Does not support ?var1=val1&var2=val2 in the path. */
void grpc_httpcli_post(grpc_exec_ctx *exec_ctx, grpc_httpcli_context *context,
grpc_polling_entity *pollent,
+ grpc_resource_quota *resource_quota,
const grpc_httpcli_request *request,
const char *body_bytes, size_t body_size,
gpr_timespec deadline, grpc_closure *on_complete,
diff --git a/src/core/lib/iomgr/endpoint.c b/src/core/lib/iomgr/endpoint.c
index f901fcf962..74fa9c45df 100644
--- a/src/core/lib/iomgr/endpoint.c
+++ b/src/core/lib/iomgr/endpoint.c
@@ -69,3 +69,7 @@ char* grpc_endpoint_get_peer(grpc_endpoint* ep) {
grpc_workqueue* grpc_endpoint_get_workqueue(grpc_endpoint* ep) {
return ep->vtable->get_workqueue(ep);
}
+
+grpc_resource_user* grpc_endpoint_get_resource_user(grpc_endpoint* ep) {
+ return ep->vtable->get_resource_user(ep);
+}
diff --git a/src/core/lib/iomgr/endpoint.h b/src/core/lib/iomgr/endpoint.h
index 910a6f6532..0ac5486ff5 100644
--- a/src/core/lib/iomgr/endpoint.h
+++ b/src/core/lib/iomgr/endpoint.h
@@ -39,6 +39,7 @@
#include <grpc/support/time.h>
#include "src/core/lib/iomgr/pollset.h"
#include "src/core/lib/iomgr/pollset_set.h"
+#include "src/core/lib/iomgr/resource_quota.h"
/* An endpoint caps a streaming channel between two communicating processes.
Examples may be: a tcp socket, <stdin+stdout>, or some shared memory. */
@@ -58,6 +59,7 @@ struct grpc_endpoint_vtable {
grpc_pollset_set *pollset);
void (*shutdown)(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep);
void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep);
+ grpc_resource_user *(*get_resource_user)(grpc_endpoint *ep);
char *(*get_peer)(grpc_endpoint *ep);
};
@@ -100,6 +102,8 @@ void grpc_endpoint_add_to_pollset_set(grpc_exec_ctx *exec_ctx,
grpc_endpoint *ep,
grpc_pollset_set *pollset_set);
+grpc_resource_user *grpc_endpoint_get_resource_user(grpc_endpoint *endpoint);
+
struct grpc_endpoint {
const grpc_endpoint_vtable *vtable;
};
diff --git a/src/core/lib/iomgr/endpoint_pair.h b/src/core/lib/iomgr/endpoint_pair.h
index 5cd78051bd..f9de0c715e 100644
--- a/src/core/lib/iomgr/endpoint_pair.h
+++ b/src/core/lib/iomgr/endpoint_pair.h
@@ -41,7 +41,8 @@ typedef struct {
grpc_endpoint *server;
} grpc_endpoint_pair;
-grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(const char *name,
- size_t read_slice_size);
+grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(
+ const char *name, grpc_resource_quota *resource_quota,
+ size_t read_slice_size);
#endif /* GRPC_CORE_LIB_IOMGR_ENDPOINT_PAIR_H */
diff --git a/src/core/lib/iomgr/endpoint_pair_posix.c b/src/core/lib/iomgr/endpoint_pair_posix.c
index ec2cd782b1..b9ff969e81 100644
--- a/src/core/lib/iomgr/endpoint_pair_posix.c
+++ b/src/core/lib/iomgr/endpoint_pair_posix.c
@@ -62,20 +62,21 @@ static void create_sockets(int sv[2]) {
GPR_ASSERT(grpc_set_socket_no_sigpipe_if_possible(sv[1]) == GRPC_ERROR_NONE);
}
-grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(const char *name,
- size_t read_slice_size) {
+grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(
+ const char *name, grpc_resource_quota *resource_quota,
+ size_t read_slice_size) {
int sv[2];
grpc_endpoint_pair p;
char *final_name;
create_sockets(sv);
gpr_asprintf(&final_name, "%s:client", name);
- p.client = grpc_tcp_create(grpc_fd_create(sv[1], final_name), read_slice_size,
- "socketpair-server");
+ p.client = grpc_tcp_create(grpc_fd_create(sv[1], final_name), resource_quota,
+ read_slice_size, "socketpair-server");
gpr_free(final_name);
gpr_asprintf(&final_name, "%s:server", name);
- p.server = grpc_tcp_create(grpc_fd_create(sv[0], final_name), read_slice_size,
- "socketpair-client");
+ p.server = grpc_tcp_create(grpc_fd_create(sv[0], final_name), resource_quota,
+ read_slice_size, "socketpair-client");
gpr_free(final_name);
return p;
}
diff --git a/src/core/lib/iomgr/resource_quota.c b/src/core/lib/iomgr/resource_quota.c
new file mode 100644
index 0000000000..bfc905845d
--- /dev/null
+++ b/src/core/lib/iomgr/resource_quota.c
@@ -0,0 +1,714 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/iomgr/resource_quota.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/useful.h>
+
+#include "src/core/lib/iomgr/combiner.h"
+
+int grpc_resource_quota_trace = 0;
+
+struct grpc_resource_quota {
+ /* refcount */
+ gpr_refcount refs;
+
+ /* Master combiner lock: all activity on a quota executes under this combiner
+ * (so no mutex is needed for this data structure)
+ */
+ grpc_combiner *combiner;
+ /* Size of the resource quota */
+ int64_t size;
+ /* Amount of free memory in the resource quota */
+ int64_t free_pool;
+
+ /* Has rq_step been scheduled to occur? */
+ bool step_scheduled;
+ /* Are we currently reclaiming memory */
+ bool reclaiming;
+ /* Closure around rq_step */
+ grpc_closure rq_step_closure;
+ /* Closure around rq_reclamation_done */
+ grpc_closure rq_reclamation_done_closure;
+
+ /* Roots of all resource user lists */
+ grpc_resource_user *roots[GRPC_RULIST_COUNT];
+
+ char *name;
+};
+
+/*******************************************************************************
+ * list management
+ */
+
+static void rulist_add_head(grpc_resource_user *resource_user,
+ grpc_rulist list) {
+ grpc_resource_quota *resource_quota = resource_user->resource_quota;
+ grpc_resource_user **root = &resource_quota->roots[list];
+ if (*root == NULL) {
+ *root = resource_user;
+ resource_user->links[list].next = resource_user->links[list].prev =
+ resource_user;
+ } else {
+ resource_user->links[list].next = *root;
+ resource_user->links[list].prev = (*root)->links[list].prev;
+ resource_user->links[list].next->links[list].prev =
+ resource_user->links[list].prev->links[list].next = resource_user;
+ *root = resource_user;
+ }
+}
+
+static void rulist_add_tail(grpc_resource_user *resource_user,
+ grpc_rulist list) {
+ grpc_resource_quota *resource_quota = resource_user->resource_quota;
+ grpc_resource_user **root = &resource_quota->roots[list];
+ if (*root == NULL) {
+ *root = resource_user;
+ resource_user->links[list].next = resource_user->links[list].prev =
+ resource_user;
+ } else {
+ resource_user->links[list].next = (*root)->links[list].next;
+ resource_user->links[list].prev = *root;
+ resource_user->links[list].next->links[list].prev =
+ resource_user->links[list].prev->links[list].next = resource_user;
+ }
+}
+
+static bool rulist_empty(grpc_resource_quota *resource_quota,
+ grpc_rulist list) {
+ return resource_quota->roots[list] == NULL;
+}
+
+static grpc_resource_user *rulist_pop_head(grpc_resource_quota *resource_quota,
+ grpc_rulist list) {
+ grpc_resource_user **root = &resource_quota->roots[list];
+ grpc_resource_user *resource_user = *root;
+ if (resource_user == NULL) {
+ return NULL;
+ }
+ if (resource_user->links[list].next == resource_user) {
+ *root = NULL;
+ } else {
+ resource_user->links[list].next->links[list].prev =
+ resource_user->links[list].prev;
+ resource_user->links[list].prev->links[list].next =
+ resource_user->links[list].next;
+ *root = resource_user->links[list].next;
+ }
+ resource_user->links[list].next = resource_user->links[list].prev = NULL;
+ return resource_user;
+}
+
+static void rulist_remove(grpc_resource_user *resource_user, grpc_rulist list) {
+ if (resource_user->links[list].next == NULL) return;
+ grpc_resource_quota *resource_quota = resource_user->resource_quota;
+ if (resource_quota->roots[list] == resource_user) {
+ resource_quota->roots[list] = resource_user->links[list].next;
+ if (resource_quota->roots[list] == resource_user) {
+ resource_quota->roots[list] = NULL;
+ }
+ }
+ resource_user->links[list].next->links[list].prev =
+ resource_user->links[list].prev;
+ resource_user->links[list].prev->links[list].next =
+ resource_user->links[list].next;
+}
+
+/*******************************************************************************
+ * resource quota state machine
+ */
+
+static bool rq_alloc(grpc_exec_ctx *exec_ctx,
+ grpc_resource_quota *resource_quota);
+static bool rq_reclaim_from_per_user_free_pool(
+ grpc_exec_ctx *exec_ctx, grpc_resource_quota *resource_quota);
+static bool rq_reclaim(grpc_exec_ctx *exec_ctx,
+ grpc_resource_quota *resource_quota, bool destructive);
+
+static void rq_step(grpc_exec_ctx *exec_ctx, void *rq, grpc_error *error) {
+ grpc_resource_quota *resource_quota = rq;
+ resource_quota->step_scheduled = false;
+ do {
+ if (rq_alloc(exec_ctx, resource_quota)) goto done;
+ } while (rq_reclaim_from_per_user_free_pool(exec_ctx, resource_quota));
+ rq_reclaim(exec_ctx, resource_quota, false) ||
+ rq_reclaim(exec_ctx, resource_quota, true);
+done:
+ grpc_resource_quota_internal_unref(exec_ctx, resource_quota);
+}
+
+static void rq_step_sched(grpc_exec_ctx *exec_ctx,
+ grpc_resource_quota *resource_quota) {
+ if (resource_quota->step_scheduled) return;
+ resource_quota->step_scheduled = true;
+ grpc_resource_quota_internal_ref(resource_quota);
+ grpc_combiner_execute_finally(exec_ctx, resource_quota->combiner,
+ &resource_quota->rq_step_closure,
+ GRPC_ERROR_NONE, false);
+}
+
+/* returns true if all allocations are completed */
+static bool rq_alloc(grpc_exec_ctx *exec_ctx,
+ grpc_resource_quota *resource_quota) {
+ grpc_resource_user *resource_user;
+ while ((resource_user = rulist_pop_head(resource_quota,
+ GRPC_RULIST_AWAITING_ALLOCATION))) {
+ gpr_mu_lock(&resource_user->mu);
+ if (resource_user->free_pool < 0 &&
+ -resource_user->free_pool <= resource_quota->free_pool) {
+ int64_t amt = -resource_user->free_pool;
+ resource_user->free_pool = 0;
+ resource_quota->free_pool -= amt;
+ if (grpc_resource_quota_trace) {
+ gpr_log(GPR_DEBUG, "RQ %s %s: grant alloc %" PRId64
+ " bytes; rq_free_pool -> %" PRId64,
+ resource_quota->name, resource_user->name, amt,
+ resource_quota->free_pool);
+ }
+ } else if (grpc_resource_quota_trace && resource_user->free_pool >= 0) {
+ gpr_log(GPR_DEBUG, "RQ %s %s: discard already satisfied alloc request",
+ resource_quota->name, resource_user->name);
+ }
+ if (resource_user->free_pool >= 0) {
+ resource_user->allocating = false;
+ grpc_exec_ctx_enqueue_list(exec_ctx, &resource_user->on_allocated, NULL);
+ gpr_mu_unlock(&resource_user->mu);
+ } else {
+ rulist_add_head(resource_user, GRPC_RULIST_AWAITING_ALLOCATION);
+ gpr_mu_unlock(&resource_user->mu);
+ return false;
+ }
+ }
+ return true;
+}
+
+/* returns true if any memory could be reclaimed from buffers */
+static bool rq_reclaim_from_per_user_free_pool(
+ grpc_exec_ctx *exec_ctx, grpc_resource_quota *resource_quota) {
+ grpc_resource_user *resource_user;
+ while ((resource_user = rulist_pop_head(resource_quota,
+ GRPC_RULIST_NON_EMPTY_FREE_POOL))) {
+ gpr_mu_lock(&resource_user->mu);
+ if (resource_user->free_pool > 0) {
+ int64_t amt = resource_user->free_pool;
+ resource_user->free_pool = 0;
+ resource_quota->free_pool += amt;
+ if (grpc_resource_quota_trace) {
+ gpr_log(GPR_DEBUG, "RQ %s %s: reclaim_from_per_user_free_pool %" PRId64
+ " bytes; rq_free_pool -> %" PRId64,
+ resource_quota->name, resource_user->name, amt,
+ resource_quota->free_pool);
+ }
+ gpr_mu_unlock(&resource_user->mu);
+ return true;
+ } else {
+ gpr_mu_unlock(&resource_user->mu);
+ }
+ }
+ return false;
+}
+
+/* returns true if reclamation is proceeding */
+static bool rq_reclaim(grpc_exec_ctx *exec_ctx,
+ grpc_resource_quota *resource_quota, bool destructive) {
+ if (resource_quota->reclaiming) return true;
+ grpc_rulist list = destructive ? GRPC_RULIST_RECLAIMER_DESTRUCTIVE
+ : GRPC_RULIST_RECLAIMER_BENIGN;
+ grpc_resource_user *resource_user = rulist_pop_head(resource_quota, list);
+ if (resource_user == NULL) return false;
+ if (grpc_resource_quota_trace) {
+ gpr_log(GPR_DEBUG, "RQ %s %s: initiate %s reclamation",
+ resource_quota->name, resource_user->name,
+ destructive ? "destructive" : "benign");
+ }
+ resource_quota->reclaiming = true;
+ grpc_resource_quota_internal_ref(resource_quota);
+ grpc_closure *c = resource_user->reclaimers[destructive];
+ resource_user->reclaimers[destructive] = NULL;
+ grpc_closure_run(exec_ctx, c, GRPC_ERROR_NONE);
+ return true;
+}
+
+/*******************************************************************************
+ * ru_slice: a slice implementation that is backed by a grpc_resource_user
+ */
+
+typedef struct {
+ gpr_slice_refcount base;
+ gpr_refcount refs;
+ grpc_resource_user *resource_user;
+ size_t size;
+} ru_slice_refcount;
+
+static void ru_slice_ref(void *p) {
+ ru_slice_refcount *rc = p;
+ gpr_ref(&rc->refs);
+}
+
+static void ru_slice_unref(void *p) {
+ ru_slice_refcount *rc = p;
+ if (gpr_unref(&rc->refs)) {
+ /* TODO(ctiller): this is dangerous, but I think safe for now:
+ we have no guarantee here that we're at a safe point for creating an
+ execution context, but we have no way of writing this code otherwise.
+ In the future: consider lifting gpr_slice to grpc, and offering an
+ internal_{ref,unref} pair that is execution context aware.
+ Alternatively,
+ make exec_ctx be thread local and 'do the right thing' (whatever that
+ is)
+ if NULL */
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_free(&exec_ctx, rc->resource_user, rc->size);
+ grpc_exec_ctx_finish(&exec_ctx);
+ gpr_free(rc);
+ }
+}
+
+static gpr_slice ru_slice_create(grpc_resource_user *resource_user,
+ size_t size) {
+ ru_slice_refcount *rc = gpr_malloc(sizeof(ru_slice_refcount) + size);
+ rc->base.ref = ru_slice_ref;
+ rc->base.unref = ru_slice_unref;
+ gpr_ref_init(&rc->refs, 1);
+ rc->resource_user = resource_user;
+ rc->size = size;
+ gpr_slice slice;
+ slice.refcount = &rc->base;
+ slice.data.refcounted.bytes = (uint8_t *)(rc + 1);
+ slice.data.refcounted.length = size;
+ return slice;
+}
+
+/*******************************************************************************
+ * grpc_resource_quota internal implementation: resource user manipulation under
+ * the combiner
+ */
+
+static void ru_allocate(grpc_exec_ctx *exec_ctx, void *ru, grpc_error *error) {
+ grpc_resource_user *resource_user = ru;
+ if (rulist_empty(resource_user->resource_quota,
+ GRPC_RULIST_AWAITING_ALLOCATION)) {
+ rq_step_sched(exec_ctx, resource_user->resource_quota);
+ }
+ rulist_add_tail(resource_user, GRPC_RULIST_AWAITING_ALLOCATION);
+}
+
+static void ru_add_to_free_pool(grpc_exec_ctx *exec_ctx, void *ru,
+ grpc_error *error) {
+ grpc_resource_user *resource_user = ru;
+ if (!rulist_empty(resource_user->resource_quota,
+ GRPC_RULIST_AWAITING_ALLOCATION) &&
+ rulist_empty(resource_user->resource_quota,
+ GRPC_RULIST_NON_EMPTY_FREE_POOL)) {
+ rq_step_sched(exec_ctx, resource_user->resource_quota);
+ }
+ rulist_add_tail(resource_user, GRPC_RULIST_NON_EMPTY_FREE_POOL);
+}
+
+static void ru_post_benign_reclaimer(grpc_exec_ctx *exec_ctx, void *ru,
+ grpc_error *error) {
+ grpc_resource_user *resource_user = ru;
+ if (!rulist_empty(resource_user->resource_quota,
+ GRPC_RULIST_AWAITING_ALLOCATION) &&
+ rulist_empty(resource_user->resource_quota,
+ GRPC_RULIST_NON_EMPTY_FREE_POOL) &&
+ rulist_empty(resource_user->resource_quota,
+ GRPC_RULIST_RECLAIMER_BENIGN)) {
+ rq_step_sched(exec_ctx, resource_user->resource_quota);
+ }
+ rulist_add_tail(resource_user, GRPC_RULIST_RECLAIMER_BENIGN);
+}
+
+static void ru_post_destructive_reclaimer(grpc_exec_ctx *exec_ctx, void *ru,
+ grpc_error *error) {
+ grpc_resource_user *resource_user = ru;
+ if (!rulist_empty(resource_user->resource_quota,
+ GRPC_RULIST_AWAITING_ALLOCATION) &&
+ rulist_empty(resource_user->resource_quota,
+ GRPC_RULIST_NON_EMPTY_FREE_POOL) &&
+ rulist_empty(resource_user->resource_quota,
+ GRPC_RULIST_RECLAIMER_BENIGN) &&
+ rulist_empty(resource_user->resource_quota,
+ GRPC_RULIST_RECLAIMER_DESTRUCTIVE)) {
+ rq_step_sched(exec_ctx, resource_user->resource_quota);
+ }
+ rulist_add_tail(resource_user, GRPC_RULIST_RECLAIMER_DESTRUCTIVE);
+}
+
+static void ru_destroy(grpc_exec_ctx *exec_ctx, void *ru, grpc_error *error) {
+ grpc_resource_user *resource_user = ru;
+ GPR_ASSERT(resource_user->allocated == 0);
+ for (int i = 0; i < GRPC_RULIST_COUNT; i++) {
+ rulist_remove(resource_user, (grpc_rulist)i);
+ }
+ grpc_exec_ctx_sched(exec_ctx, resource_user->reclaimers[0],
+ GRPC_ERROR_CANCELLED, NULL);
+ grpc_exec_ctx_sched(exec_ctx, resource_user->reclaimers[1],
+ GRPC_ERROR_CANCELLED, NULL);
+ grpc_exec_ctx_sched(exec_ctx, (grpc_closure *)gpr_atm_no_barrier_load(
+ &resource_user->on_done_destroy_closure),
+ GRPC_ERROR_NONE, NULL);
+ if (resource_user->free_pool != 0) {
+ resource_user->resource_quota->free_pool += resource_user->free_pool;
+ rq_step_sched(exec_ctx, resource_user->resource_quota);
+ }
+}
+
+static void ru_allocated_slices(grpc_exec_ctx *exec_ctx, void *arg,
+ grpc_error *error) {
+ grpc_resource_user_slice_allocator *slice_allocator = arg;
+ if (error == GRPC_ERROR_NONE) {
+ for (size_t i = 0; i < slice_allocator->count; i++) {
+ gpr_slice_buffer_add_indexed(
+ slice_allocator->dest, ru_slice_create(slice_allocator->resource_user,
+ slice_allocator->length));
+ }
+ }
+ grpc_closure_run(exec_ctx, &slice_allocator->on_done, GRPC_ERROR_REF(error));
+}
+
+/*******************************************************************************
+ * grpc_resource_quota internal implementation: quota manipulation under the
+ * combiner
+ */
+
+typedef struct {
+ int64_t size;
+ grpc_resource_quota *resource_quota;
+ grpc_closure closure;
+} rq_resize_args;
+
+static void rq_resize(grpc_exec_ctx *exec_ctx, void *args, grpc_error *error) {
+ rq_resize_args *a = args;
+ int64_t delta = a->size - a->resource_quota->size;
+ a->resource_quota->size += delta;
+ a->resource_quota->free_pool += delta;
+ rq_step_sched(exec_ctx, a->resource_quota);
+ grpc_resource_quota_internal_unref(exec_ctx, a->resource_quota);
+ gpr_free(a);
+}
+
+static void rq_reclamation_done(grpc_exec_ctx *exec_ctx, void *rq,
+ grpc_error *error) {
+ grpc_resource_quota *resource_quota = rq;
+ resource_quota->reclaiming = false;
+ rq_step_sched(exec_ctx, resource_quota);
+ grpc_resource_quota_internal_unref(exec_ctx, resource_quota);
+}
+
+/*******************************************************************************
+ * grpc_resource_quota api
+ */
+
+/* Public API */
+grpc_resource_quota *grpc_resource_quota_create(const char *name) {
+ grpc_resource_quota *resource_quota = gpr_malloc(sizeof(*resource_quota));
+ gpr_ref_init(&resource_quota->refs, 1);
+ resource_quota->combiner = grpc_combiner_create(NULL);
+ resource_quota->free_pool = INT64_MAX;
+ resource_quota->size = INT64_MAX;
+ resource_quota->step_scheduled = false;
+ resource_quota->reclaiming = false;
+ if (name != NULL) {
+ resource_quota->name = gpr_strdup(name);
+ } else {
+ gpr_asprintf(&resource_quota->name, "anonymous_pool_%" PRIxPTR,
+ (intptr_t)resource_quota);
+ }
+ grpc_closure_init(&resource_quota->rq_step_closure, rq_step, resource_quota);
+ grpc_closure_init(&resource_quota->rq_reclamation_done_closure,
+ rq_reclamation_done, resource_quota);
+ for (int i = 0; i < GRPC_RULIST_COUNT; i++) {
+ resource_quota->roots[i] = NULL;
+ }
+ return resource_quota;
+}
+
+void grpc_resource_quota_internal_unref(grpc_exec_ctx *exec_ctx,
+ grpc_resource_quota *resource_quota) {
+ if (gpr_unref(&resource_quota->refs)) {
+ grpc_combiner_destroy(exec_ctx, resource_quota->combiner);
+ gpr_free(resource_quota->name);
+ gpr_free(resource_quota);
+ }
+}
+
+/* Public API */
+void grpc_resource_quota_unref(grpc_resource_quota *resource_quota) {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_quota_internal_unref(&exec_ctx, resource_quota);
+ grpc_exec_ctx_finish(&exec_ctx);
+}
+
+grpc_resource_quota *grpc_resource_quota_internal_ref(
+ grpc_resource_quota *resource_quota) {
+ gpr_ref(&resource_quota->refs);
+ return resource_quota;
+}
+
+/* Public API */
+void grpc_resource_quota_ref(grpc_resource_quota *resource_quota) {
+ grpc_resource_quota_internal_ref(resource_quota);
+}
+
+/* Public API */
+void grpc_resource_quota_resize(grpc_resource_quota *resource_quota,
+ size_t size) {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ rq_resize_args *a = gpr_malloc(sizeof(*a));
+ a->resource_quota = grpc_resource_quota_internal_ref(resource_quota);
+ a->size = (int64_t)size;
+ grpc_closure_init(&a->closure, rq_resize, a);
+ grpc_combiner_execute(&exec_ctx, resource_quota->combiner, &a->closure,
+ GRPC_ERROR_NONE, false);
+ grpc_exec_ctx_finish(&exec_ctx);
+}
+
+/*******************************************************************************
+ * grpc_resource_user channel args api
+ */
+
+grpc_resource_quota *grpc_resource_quota_from_channel_args(
+ const grpc_channel_args *channel_args) {
+ for (size_t i = 0; i < channel_args->num_args; i++) {
+ if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_RESOURCE_QUOTA)) {
+ if (channel_args->args[i].type == GRPC_ARG_POINTER) {
+ return grpc_resource_quota_internal_ref(
+ channel_args->args[i].value.pointer.p);
+ } else {
+ gpr_log(GPR_DEBUG, GRPC_ARG_RESOURCE_QUOTA " should be a pointer");
+ }
+ }
+ }
+ return grpc_resource_quota_create(NULL);
+}
+
+static void *rq_copy(void *rq) {
+ grpc_resource_quota_ref(rq);
+ return rq;
+}
+
+static void rq_destroy(void *rq) { grpc_resource_quota_unref(rq); }
+
+static int rq_cmp(void *a, void *b) { return GPR_ICMP(a, b); }
+
+const grpc_arg_pointer_vtable *grpc_resource_quota_arg_vtable(void) {
+ static const grpc_arg_pointer_vtable vtable = {rq_copy, rq_destroy, rq_cmp};
+ return &vtable;
+}
+
+/*******************************************************************************
+ * grpc_resource_user api
+ */
+
+void grpc_resource_user_init(grpc_resource_user *resource_user,
+ grpc_resource_quota *resource_quota,
+ const char *name) {
+ resource_user->resource_quota =
+ grpc_resource_quota_internal_ref(resource_quota);
+ grpc_closure_init(&resource_user->allocate_closure, &ru_allocate,
+ resource_user);
+ grpc_closure_init(&resource_user->add_to_free_pool_closure,
+ &ru_add_to_free_pool, resource_user);
+ grpc_closure_init(&resource_user->post_reclaimer_closure[0],
+ &ru_post_benign_reclaimer, resource_user);
+ grpc_closure_init(&resource_user->post_reclaimer_closure[1],
+ &ru_post_destructive_reclaimer, resource_user);
+ grpc_closure_init(&resource_user->destroy_closure, &ru_destroy,
+ resource_user);
+ gpr_mu_init(&resource_user->mu);
+ resource_user->allocated = 0;
+ resource_user->free_pool = 0;
+ grpc_closure_list_init(&resource_user->on_allocated);
+ resource_user->allocating = false;
+ resource_user->added_to_free_pool = false;
+ gpr_atm_no_barrier_store(&resource_user->on_done_destroy_closure, 0);
+ resource_user->reclaimers[0] = NULL;
+ resource_user->reclaimers[1] = NULL;
+ for (int i = 0; i < GRPC_RULIST_COUNT; i++) {
+ resource_user->links[i].next = resource_user->links[i].prev = NULL;
+ }
+ if (name != NULL) {
+ resource_user->name = gpr_strdup(name);
+ } else {
+ gpr_asprintf(&resource_user->name, "anonymous_resource_user_%" PRIxPTR,
+ (intptr_t)resource_user);
+ }
+}
+
+void grpc_resource_user_shutdown(grpc_exec_ctx *exec_ctx,
+ grpc_resource_user *resource_user,
+ grpc_closure *on_done) {
+ gpr_mu_lock(&resource_user->mu);
+ GPR_ASSERT(gpr_atm_no_barrier_load(&resource_user->on_done_destroy_closure) ==
+ 0);
+ gpr_atm_no_barrier_store(&resource_user->on_done_destroy_closure,
+ (gpr_atm)on_done);
+ if (resource_user->allocated == 0) {
+ grpc_combiner_execute(exec_ctx, resource_user->resource_quota->combiner,
+ &resource_user->destroy_closure, GRPC_ERROR_NONE,
+ false);
+ }
+ gpr_mu_unlock(&resource_user->mu);
+}
+
+void grpc_resource_user_destroy(grpc_exec_ctx *exec_ctx,
+ grpc_resource_user *resource_user) {
+ grpc_resource_quota_internal_unref(exec_ctx, resource_user->resource_quota);
+ gpr_mu_destroy(&resource_user->mu);
+ gpr_free(resource_user->name);
+}
+
+void grpc_resource_user_alloc(grpc_exec_ctx *exec_ctx,
+ grpc_resource_user *resource_user, size_t size,
+ grpc_closure *optional_on_done) {
+ gpr_mu_lock(&resource_user->mu);
+ grpc_closure *on_done_destroy = (grpc_closure *)gpr_atm_no_barrier_load(
+ &resource_user->on_done_destroy_closure);
+ if (on_done_destroy != NULL) {
+ /* already shutdown */
+ if (grpc_resource_quota_trace) {
+ gpr_log(GPR_DEBUG, "RQ %s %s: alloc %" PRIdPTR " after shutdown",
+ resource_user->resource_quota->name, resource_user->name, size);
+ }
+ grpc_exec_ctx_sched(
+ exec_ctx, optional_on_done,
+ GRPC_ERROR_CREATE("Buffer pool user is already shutdown"), NULL);
+ gpr_mu_unlock(&resource_user->mu);
+ return;
+ }
+ resource_user->allocated += (int64_t)size;
+ resource_user->free_pool -= (int64_t)size;
+ if (grpc_resource_quota_trace) {
+ gpr_log(GPR_DEBUG, "RQ %s %s: alloc %" PRIdPTR "; allocated -> %" PRId64
+ ", free_pool -> %" PRId64,
+ resource_user->resource_quota->name, resource_user->name, size,
+ resource_user->allocated, resource_user->free_pool);
+ }
+ if (resource_user->free_pool < 0) {
+ grpc_closure_list_append(&resource_user->on_allocated, optional_on_done,
+ GRPC_ERROR_NONE);
+ if (!resource_user->allocating) {
+ resource_user->allocating = true;
+ grpc_combiner_execute(exec_ctx, resource_user->resource_quota->combiner,
+ &resource_user->allocate_closure, GRPC_ERROR_NONE,
+ false);
+ }
+ } else {
+ grpc_exec_ctx_sched(exec_ctx, optional_on_done, GRPC_ERROR_NONE, NULL);
+ }
+ gpr_mu_unlock(&resource_user->mu);
+}
+
+void grpc_resource_user_free(grpc_exec_ctx *exec_ctx,
+ grpc_resource_user *resource_user, size_t size) {
+ gpr_mu_lock(&resource_user->mu);
+ GPR_ASSERT(resource_user->allocated >= (int64_t)size);
+ bool was_zero_or_negative = resource_user->free_pool <= 0;
+ resource_user->free_pool += (int64_t)size;
+ resource_user->allocated -= (int64_t)size;
+ if (grpc_resource_quota_trace) {
+ gpr_log(GPR_DEBUG, "RQ %s %s: free %" PRIdPTR "; allocated -> %" PRId64
+ ", free_pool -> %" PRId64,
+ resource_user->resource_quota->name, resource_user->name, size,
+ resource_user->allocated, resource_user->free_pool);
+ }
+ bool is_bigger_than_zero = resource_user->free_pool > 0;
+ if (is_bigger_than_zero && was_zero_or_negative &&
+ !resource_user->added_to_free_pool) {
+ resource_user->added_to_free_pool = true;
+ grpc_combiner_execute(exec_ctx, resource_user->resource_quota->combiner,
+ &resource_user->add_to_free_pool_closure,
+ GRPC_ERROR_NONE, false);
+ }
+ grpc_closure *on_done_destroy = (grpc_closure *)gpr_atm_no_barrier_load(
+ &resource_user->on_done_destroy_closure);
+ if (on_done_destroy != NULL && resource_user->allocated == 0) {
+ grpc_combiner_execute(exec_ctx, resource_user->resource_quota->combiner,
+ &resource_user->destroy_closure, GRPC_ERROR_NONE,
+ false);
+ }
+ gpr_mu_unlock(&resource_user->mu);
+}
+
+void grpc_resource_user_post_reclaimer(grpc_exec_ctx *exec_ctx,
+ grpc_resource_user *resource_user,
+ bool destructive,
+ grpc_closure *closure) {
+ if (gpr_atm_acq_load(&resource_user->on_done_destroy_closure) == 0) {
+ GPR_ASSERT(resource_user->reclaimers[destructive] == NULL);
+ resource_user->reclaimers[destructive] = closure;
+ grpc_combiner_execute(exec_ctx, resource_user->resource_quota->combiner,
+ &resource_user->post_reclaimer_closure[destructive],
+ GRPC_ERROR_NONE, false);
+ } else {
+ grpc_exec_ctx_sched(exec_ctx, closure, GRPC_ERROR_CANCELLED, NULL);
+ }
+}
+
+void grpc_resource_user_finish_reclamation(grpc_exec_ctx *exec_ctx,
+ grpc_resource_user *resource_user) {
+ if (grpc_resource_quota_trace) {
+ gpr_log(GPR_DEBUG, "RQ %s %s: reclamation complete",
+ resource_user->resource_quota->name, resource_user->name);
+ }
+ grpc_combiner_execute(
+ exec_ctx, resource_user->resource_quota->combiner,
+ &resource_user->resource_quota->rq_reclamation_done_closure,
+ GRPC_ERROR_NONE, false);
+}
+
+void grpc_resource_user_slice_allocator_init(
+ grpc_resource_user_slice_allocator *slice_allocator,
+ grpc_resource_user *resource_user, grpc_iomgr_cb_func cb, void *p) {
+ grpc_closure_init(&slice_allocator->on_allocated, ru_allocated_slices,
+ slice_allocator);
+ grpc_closure_init(&slice_allocator->on_done, cb, p);
+ slice_allocator->resource_user = resource_user;
+}
+
+void grpc_resource_user_alloc_slices(
+ grpc_exec_ctx *exec_ctx,
+ grpc_resource_user_slice_allocator *slice_allocator, size_t length,
+ size_t count, gpr_slice_buffer *dest) {
+ slice_allocator->length = length;
+ slice_allocator->count = count;
+ slice_allocator->dest = dest;
+ grpc_resource_user_alloc(exec_ctx, slice_allocator->resource_user,
+ count * length, &slice_allocator->on_allocated);
+}
diff --git a/src/core/lib/iomgr/resource_quota.h b/src/core/lib/iomgr/resource_quota.h
new file mode 100644
index 0000000000..6dfac55f88
--- /dev/null
+++ b/src/core/lib/iomgr/resource_quota.h
@@ -0,0 +1,224 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_IOMGR_RESOURCE_QUOTA_H
+#define GRPC_CORE_LIB_IOMGR_RESOURCE_QUOTA_H
+
+#include <grpc/grpc.h>
+
+#include "src/core/lib/iomgr/exec_ctx.h"
+
+/** \file Tracks resource usage against a pool.
+
+ The current implementation tracks only memory usage, but in the future
+ this may be extended to (for example) threads and file descriptors.
+
+ A grpc_resource_quota represents the pooled resources, and
+ grpc_resource_user instances attach to the quota and consume those
+ resources. They also offer a vector for reclamation: if we become
+ resource constrained, grpc_resource_user instances are asked (in turn) to
+ free up whatever they can so that the system as a whole can make progress.
+
+ There are three kinds of reclamation that take place, in order of increasing
+ invasiveness:
+ - an internal reclamation, where cached resource at the resource user level
+ is returned to the quota
+ - a benign reclamation phase, whereby resources that are in use but are not
+ helping anything make progress are reclaimed
+ - a destructive reclamation, whereby resources that are helping something
+ make progress may be enacted so that at least one part of the system can
+ complete.
+
+ Only one reclamation will be outstanding for a given quota at a given time.
+ On each reclamation attempt, the kinds of reclamation are tried in order of
+ increasing invasiveness, stopping at the first one that succeeds. Thus, on a
+ given reclamation attempt, if internal and benign reclamation both fail, it
+ will wind up doing a destructive reclamation. However, the next reclamation
+ attempt may then be able to get what it needs via internal or benign
+ reclamation, due to resources that may have been freed up by the destructive
+ reclamation in the previous attempt.
+
+ Future work will be to expose the current resource pressure so that back
+ pressure can be applied to avoid reclamation phases starting.
+
+ Resource users own references to resource quotas, and resource quotas
+ maintain lists of users (which users arrange to leave before they are
+ destroyed) */
+
+extern int grpc_resource_quota_trace;
+
+grpc_resource_quota *grpc_resource_quota_internal_ref(
+ grpc_resource_quota *resource_quota);
+void grpc_resource_quota_internal_unref(grpc_exec_ctx *exec_ctx,
+ grpc_resource_quota *resource_quota);
+grpc_resource_quota *grpc_resource_quota_from_channel_args(
+ const grpc_channel_args *channel_args);
+
+/* Resource users are kept in (potentially) several intrusive linked lists
+ at once. These are the list names. */
+typedef enum {
+ /* Resource users that are waiting for an allocation */
+ GRPC_RULIST_AWAITING_ALLOCATION,
+ /* Resource users that have free memory available for internal reclamation */
+ GRPC_RULIST_NON_EMPTY_FREE_POOL,
+ /* Resource users that have published a benign reclamation is available */
+ GRPC_RULIST_RECLAIMER_BENIGN,
+ /* Resource users that have published a destructive reclamation is
+ available */
+ GRPC_RULIST_RECLAIMER_DESTRUCTIVE,
+ /* Number of lists: must be last */
+ GRPC_RULIST_COUNT
+} grpc_rulist;
+
+typedef struct grpc_resource_user grpc_resource_user;
+
+/* Internal linked list pointers for a resource user */
+typedef struct {
+ grpc_resource_user *next;
+ grpc_resource_user *prev;
+} grpc_resource_user_link;
+
+struct grpc_resource_user {
+ /* The quota this resource user consumes from */
+ grpc_resource_quota *resource_quota;
+
+ /* Closure to schedule an allocation under the resource quota combiner lock */
+ grpc_closure allocate_closure;
+ /* Closure to publish a non empty free pool under the resource quota combiner
+ lock */
+ grpc_closure add_to_free_pool_closure;
+
+ gpr_mu mu;
+ /* Total allocated memory outstanding by this resource user in bytes;
+ always positive */
+ int64_t allocated;
+ /* The amount of memory (in bytes) this user has cached for its own use: to
+ avoid quota contention, each resource user can keep some memory in
+ addition to what it is immediately using (e.g., for caching), and the quota
+ can pull it back under memory pressure.
+ This value can become negative if more memory has been requested than
+ existed in the free pool, at which point the quota is consulted to bring
+ this value non-negative (asynchronously). */
+ int64_t free_pool;
+ /* A list of closures to call once free_pool becomes non-negative - ie when
+ all outstanding allocations have been granted. */
+ grpc_closure_list on_allocated;
+ /* True if we are currently trying to allocate from the quota, false if not */
+ bool allocating;
+ /* True if we are currently trying to add ourselves to the non-free quota
+ list, false otherwise */
+ bool added_to_free_pool;
+
+ /* Reclaimers: index 0 is the benign reclaimer, 1 is the destructive reclaimer
+ */
+ grpc_closure *reclaimers[2];
+ /* Trampoline closures to finish reclamation and re-enter the quota combiner
+ lock */
+ grpc_closure post_reclaimer_closure[2];
+
+ /* Closure to execute under the quota combiner to de-register and shutdown the
+ resource user */
+ grpc_closure destroy_closure;
+ /* User supplied closure to call once the user has finished shutting down AND
+ all outstanding allocations have been freed. Real type is grpc_closure*,
+ but it's stored as an atomic to avoid a mutex on some fast paths. */
+ gpr_atm on_done_destroy_closure;
+
+ /* Links in the various grpc_rulist lists */
+ grpc_resource_user_link links[GRPC_RULIST_COUNT];
+
+ /* The name of this resource user, for debugging/tracing */
+ char *name;
+};
+
+void grpc_resource_user_init(grpc_resource_user *resource_user,
+ grpc_resource_quota *resource_quota,
+ const char *name);
+void grpc_resource_user_shutdown(grpc_exec_ctx *exec_ctx,
+ grpc_resource_user *resource_user,
+ grpc_closure *on_done);
+void grpc_resource_user_destroy(grpc_exec_ctx *exec_ctx,
+ grpc_resource_user *resource_user);
+
+/* Allocate from the resource user (and its quota).
+ If optional_on_done is NULL, then allocate immediately. This may push the
+ quota over-limit, at which point reclamation will kick in.
+ If optional_on_done is non-NULL, it will be scheduled when the allocation has
+ been granted by the quota. */
+void grpc_resource_user_alloc(grpc_exec_ctx *exec_ctx,
+ grpc_resource_user *resource_user, size_t size,
+ grpc_closure *optional_on_done);
+/* Release memory back to the quota */
+void grpc_resource_user_free(grpc_exec_ctx *exec_ctx,
+ grpc_resource_user *resource_user, size_t size);
+/* Post a memory reclaimer to the resource user. Only one benign and one
+ destructive reclaimer can be posted at once. When executed, the reclaimer
+ MUST call grpc_resource_user_finish_reclamation before it completes, to
+ return control to the resource quota. */
+void grpc_resource_user_post_reclaimer(grpc_exec_ctx *exec_ctx,
+ grpc_resource_user *resource_user,
+ bool destructive, grpc_closure *closure);
+/* Finish a reclamation step */
+void grpc_resource_user_finish_reclamation(grpc_exec_ctx *exec_ctx,
+ grpc_resource_user *resource_user);
+
+/* Helper to allocate slices from a resource user */
+typedef struct grpc_resource_user_slice_allocator {
+ /* Closure for when a resource user allocation completes */
+ grpc_closure on_allocated;
+ /* Closure to call when slices have been allocated */
+ grpc_closure on_done;
+ /* Length of slices to allocate on the current request */
+ size_t length;
+ /* Number of slices to allocate on the current request */
+ size_t count;
+ /* Destination for slices to allocate on the current request */
+ gpr_slice_buffer *dest;
+ /* Parent resource user */
+ grpc_resource_user *resource_user;
+} grpc_resource_user_slice_allocator;
+
+/* Initialize a slice allocator.
+ When an allocation is completed, calls \a cb with arg \p. */
+void grpc_resource_user_slice_allocator_init(
+ grpc_resource_user_slice_allocator *slice_allocator,
+ grpc_resource_user *resource_user, grpc_iomgr_cb_func cb, void *p);
+
+/* Allocate \a count slices of length \a length into \a dest. Only one request
+ can be outstanding at a time. */
+void grpc_resource_user_alloc_slices(
+ grpc_exec_ctx *exec_ctx,
+ grpc_resource_user_slice_allocator *slice_allocator, size_t length,
+ size_t count, gpr_slice_buffer *dest);
+
+#endif /* GRPC_CORE_LIB_IOMGR_RESOURCE_QUOTA_H */
diff --git a/src/core/lib/iomgr/tcp_client.h b/src/core/lib/iomgr/tcp_client.h
index fe1e7f4d3e..18e6e60ebc 100644
--- a/src/core/lib/iomgr/tcp_client.h
+++ b/src/core/lib/iomgr/tcp_client.h
@@ -39,6 +39,10 @@
#include "src/core/lib/iomgr/pollset_set.h"
#include "src/core/lib/iomgr/resolve_address.h"
+/* Channel arg (integer) setting how large a slice to try and read from the wire
+ each time recvmsg (or equivalent) is called */
+#define GRPC_ARG_TCP_READ_CHUNK_SIZE "grpc.experimental.tcp_read_chunk_size"
+
/* Asynchronously connect to an address (specified as (addr, len)), and call
cb with arg and the completed connection when done (or call cb with arg and
NULL on failure).
@@ -47,6 +51,7 @@
void grpc_tcp_client_connect(grpc_exec_ctx *exec_ctx, grpc_closure *on_connect,
grpc_endpoint **endpoint,
grpc_pollset_set *interested_parties,
+ const grpc_channel_args *channel_args,
const grpc_resolved_address *addr,
gpr_timespec deadline);
diff --git a/src/core/lib/iomgr/tcp_client_posix.c b/src/core/lib/iomgr/tcp_client_posix.c
index e7ae1ef695..bc08c94ee0 100644
--- a/src/core/lib/iomgr/tcp_client_posix.c
+++ b/src/core/lib/iomgr/tcp_client_posix.c
@@ -35,7 +35,7 @@
#ifdef GRPC_POSIX_SOCKET
-#include "src/core/lib/iomgr/tcp_client.h"
+#include "src/core/lib/iomgr/tcp_client_posix.h"
#include <errno.h>
#include <netinet/in.h>
@@ -47,6 +47,7 @@
#include <grpc/support/string_util.h>
#include <grpc/support/time.h>
+#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/iomgr/ev_posix.h"
#include "src/core/lib/iomgr/iomgr_posix.h"
#include "src/core/lib/iomgr/sockaddr_utils.h"
@@ -69,6 +70,7 @@ typedef struct {
char *addr_str;
grpc_endpoint **ep;
grpc_closure *closure;
+ grpc_channel_args *channel_args;
} async_connect;
static grpc_error *prepare_socket(const grpc_resolved_address *addr, int fd) {
@@ -114,10 +116,39 @@ static void tc_on_alarm(grpc_exec_ctx *exec_ctx, void *acp, grpc_error *error) {
if (done) {
gpr_mu_destroy(&ac->mu);
gpr_free(ac->addr_str);
+ grpc_channel_args_destroy(ac->channel_args);
gpr_free(ac);
}
}
+grpc_endpoint *grpc_tcp_client_create_from_fd(
+ grpc_exec_ctx *exec_ctx, grpc_fd *fd, const grpc_channel_args *channel_args,
+ const char *addr_str) {
+ size_t tcp_read_chunk_size = GRPC_TCP_DEFAULT_READ_SLICE_SIZE;
+ grpc_resource_quota *resource_quota = grpc_resource_quota_create(NULL);
+ if (channel_args != NULL) {
+ for (size_t i = 0; i < channel_args->num_args; i++) {
+ if (0 ==
+ strcmp(channel_args->args[i].key, GRPC_ARG_TCP_READ_CHUNK_SIZE)) {
+ grpc_integer_options options = {(int)tcp_read_chunk_size, 1,
+ 8 * 1024 * 1024};
+ tcp_read_chunk_size = (size_t)grpc_channel_arg_get_integer(
+ &channel_args->args[i], options);
+ } else if (0 ==
+ strcmp(channel_args->args[i].key, GRPC_ARG_RESOURCE_QUOTA)) {
+ grpc_resource_quota_internal_unref(exec_ctx, resource_quota);
+ resource_quota = grpc_resource_quota_internal_ref(
+ channel_args->args[i].value.pointer.p);
+ }
+ }
+ }
+
+ grpc_endpoint *ep =
+ grpc_tcp_create(fd, resource_quota, tcp_read_chunk_size, addr_str);
+ grpc_resource_quota_internal_unref(exec_ctx, resource_quota);
+ return ep;
+}
+
static void on_writable(grpc_exec_ctx *exec_ctx, void *acp, grpc_error *error) {
async_connect *ac = acp;
int so_error = 0;
@@ -165,7 +196,8 @@ static void on_writable(grpc_exec_ctx *exec_ctx, void *acp, grpc_error *error) {
switch (so_error) {
case 0:
grpc_pollset_set_del_fd(exec_ctx, ac->interested_parties, fd);
- *ep = grpc_tcp_create(fd, GRPC_TCP_DEFAULT_READ_SLICE_SIZE, ac->addr_str);
+ *ep = grpc_tcp_client_create_from_fd(exec_ctx, fd, ac->channel_args,
+ ac->addr_str);
fd = NULL;
break;
case ENOBUFS:
@@ -215,6 +247,7 @@ finish:
if (done) {
gpr_mu_destroy(&ac->mu);
gpr_free(ac->addr_str);
+ grpc_channel_args_destroy(ac->channel_args);
gpr_free(ac);
}
grpc_exec_ctx_sched(exec_ctx, closure, error, NULL);
@@ -223,6 +256,7 @@ finish:
static void tcp_client_connect_impl(grpc_exec_ctx *exec_ctx,
grpc_closure *closure, grpc_endpoint **ep,
grpc_pollset_set *interested_parties,
+ const grpc_channel_args *channel_args,
const grpc_resolved_address *addr,
gpr_timespec deadline) {
int fd;
@@ -270,7 +304,8 @@ static void tcp_client_connect_impl(grpc_exec_ctx *exec_ctx,
fdobj = grpc_fd_create(fd, name);
if (err >= 0) {
- *ep = grpc_tcp_create(fdobj, GRPC_TCP_DEFAULT_READ_SLICE_SIZE, addr_str);
+ *ep =
+ grpc_tcp_client_create_from_fd(exec_ctx, fdobj, channel_args, addr_str);
grpc_exec_ctx_sched(exec_ctx, closure, GRPC_ERROR_NONE, NULL);
goto done;
}
@@ -295,6 +330,7 @@ static void tcp_client_connect_impl(grpc_exec_ctx *exec_ctx,
ac->refs = 2;
ac->write_closure.cb = on_writable;
ac->write_closure.cb_arg = ac;
+ ac->channel_args = grpc_channel_args_copy(channel_args);
if (grpc_tcp_trace) {
gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: asynchronously connecting",
@@ -316,16 +352,18 @@ done:
// overridden by api_fuzzer.c
void (*grpc_tcp_client_connect_impl)(
grpc_exec_ctx *exec_ctx, grpc_closure *closure, grpc_endpoint **ep,
- grpc_pollset_set *interested_parties, const grpc_resolved_address *addr,
+ grpc_pollset_set *interested_parties, const grpc_channel_args *channel_args,
+ const grpc_resolved_address *addr,
gpr_timespec deadline) = tcp_client_connect_impl;
void grpc_tcp_client_connect(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
grpc_endpoint **ep,
grpc_pollset_set *interested_parties,
+ const grpc_channel_args *channel_args,
const grpc_resolved_address *addr,
gpr_timespec deadline) {
- grpc_tcp_client_connect_impl(exec_ctx, closure, ep, interested_parties, addr,
- deadline);
+ grpc_tcp_client_connect_impl(exec_ctx, closure, ep, interested_parties,
+ channel_args, addr, deadline);
}
#endif
diff --git a/src/core/lib/iomgr/tcp_client_posix.h b/src/core/lib/iomgr/tcp_client_posix.h
new file mode 100644
index 0000000000..efc5fcd5bb
--- /dev/null
+++ b/src/core/lib/iomgr/tcp_client_posix.h
@@ -0,0 +1,45 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_IOMGR_TCP_CLIENT_POSIX_H
+#define GRPC_CORE_LIB_IOMGR_TCP_CLIENT_POSIX_H
+
+#include "src/core/lib/iomgr/endpoint.h"
+#include "src/core/lib/iomgr/ev_posix.h"
+#include "src/core/lib/iomgr/tcp_client.h"
+
+grpc_endpoint *grpc_tcp_client_create_from_fd(
+ grpc_exec_ctx *exec_ctx, grpc_fd *fd, const grpc_channel_args *channel_args,
+ const char *addr_str);
+
+#endif /* GRPC_CORE_LIB_IOMGR_TCP_CLIENT_POSIX_H */
diff --git a/src/core/lib/iomgr/tcp_posix.c b/src/core/lib/iomgr/tcp_posix.c
index 18c63cfbae..880af93ee1 100644
--- a/src/core/lib/iomgr/tcp_posix.c
+++ b/src/core/lib/iomgr/tcp_posix.c
@@ -80,6 +80,7 @@ typedef struct {
msg_iovlen_type iov_size; /* Number of slices to allocate per read attempt */
size_t slice_size;
gpr_refcount refcount;
+ gpr_atm shutdown_count;
/* garbage after the last read */
gpr_slice_buffer last_read_buffer;
@@ -100,15 +101,29 @@ typedef struct {
grpc_closure write_closure;
char *peer_string;
+
+ grpc_resource_user resource_user;
+ grpc_resource_user_slice_allocator slice_allocator;
} grpc_tcp;
static void tcp_handle_read(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */,
grpc_error *error);
static void tcp_handle_write(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */,
grpc_error *error);
+static void tcp_unref_closure(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */,
+ grpc_error *error);
+
+static void tcp_maybe_shutdown_resource_user(grpc_exec_ctx *exec_ctx,
+ grpc_tcp *tcp) {
+ if (gpr_atm_full_fetch_add(&tcp->shutdown_count, 1) == 0) {
+ grpc_resource_user_shutdown(exec_ctx, &tcp->resource_user,
+ grpc_closure_create(tcp_unref_closure, tcp));
+ }
+}
static void tcp_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) {
grpc_tcp *tcp = (grpc_tcp *)ep;
+ tcp_maybe_shutdown_resource_user(exec_ctx, tcp);
grpc_fd_shutdown(exec_ctx, tcp->em_fd);
}
@@ -116,6 +131,7 @@ static void tcp_free(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) {
grpc_fd_orphan(exec_ctx, tcp->em_fd, tcp->release_fd_cb, tcp->release_fd,
"tcp_unref_orphan");
gpr_slice_buffer_destroy(&tcp->last_read_buffer);
+ grpc_resource_user_destroy(exec_ctx, &tcp->resource_user);
gpr_free(tcp->peer_string);
gpr_free(tcp);
}
@@ -152,9 +168,16 @@ static void tcp_unref(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) {
static void tcp_ref(grpc_tcp *tcp) { gpr_ref(&tcp->refcount); }
#endif
+static void tcp_unref_closure(grpc_exec_ctx *exec_ctx, void *arg,
+ grpc_error *error) {
+ TCP_UNREF(exec_ctx, arg, "resource_user");
+}
+
static void tcp_destroy(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) {
grpc_network_status_unregister_endpoint(ep);
grpc_tcp *tcp = (grpc_tcp *)ep;
+ tcp_maybe_shutdown_resource_user(exec_ctx, tcp);
+ gpr_slice_buffer_reset_and_unref(&tcp->last_read_buffer);
TCP_UNREF(exec_ctx, tcp, "destroy");
}
@@ -181,7 +204,7 @@ static void call_read_cb(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp,
}
#define MAX_READ_IOVEC 4
-static void tcp_continue_read(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) {
+static void tcp_do_read(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) {
struct msghdr msg;
struct iovec iov[MAX_READ_IOVEC];
ssize_t read_bytes;
@@ -192,10 +215,6 @@ static void tcp_continue_read(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) {
GPR_ASSERT(tcp->incoming_buffer->count <= MAX_READ_IOVEC);
GPR_TIMER_BEGIN("tcp_continue_read", 0);
- while (tcp->incoming_buffer->count < (size_t)tcp->iov_size) {
- gpr_slice_buffer_add_indexed(tcp->incoming_buffer,
- gpr_slice_malloc(tcp->slice_size));
- }
for (i = 0; i < tcp->incoming_buffer->count; i++) {
iov[i].iov_base = GPR_SLICE_START_PTR(tcp->incoming_buffer->slices[i]);
iov[i].iov_len = GPR_SLICE_LENGTH(tcp->incoming_buffer->slices[i]);
@@ -232,7 +251,7 @@ static void tcp_continue_read(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) {
} else if (read_bytes == 0) {
/* 0 read size ==> end of stream */
gpr_slice_buffer_reset_and_unref(tcp->incoming_buffer);
- call_read_cb(exec_ctx, tcp, GRPC_ERROR_CREATE("EOF"));
+ call_read_cb(exec_ctx, tcp, GRPC_ERROR_CREATE("Socket closed"));
TCP_UNREF(exec_ctx, tcp, "read");
} else {
GPR_ASSERT((size_t)read_bytes <= tcp->incoming_buffer->length);
@@ -252,6 +271,30 @@ static void tcp_continue_read(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) {
GPR_TIMER_END("tcp_continue_read", 0);
}
+static void tcp_read_allocation_done(grpc_exec_ctx *exec_ctx, void *tcpp,
+ grpc_error *error) {
+ grpc_tcp *tcp = tcpp;
+ if (error != GRPC_ERROR_NONE) {
+ gpr_slice_buffer_reset_and_unref(tcp->incoming_buffer);
+ gpr_slice_buffer_reset_and_unref(&tcp->last_read_buffer);
+ call_read_cb(exec_ctx, tcp, GRPC_ERROR_REF(error));
+ TCP_UNREF(exec_ctx, tcp, "read");
+ } else {
+ tcp_do_read(exec_ctx, tcp);
+ }
+}
+
+static void tcp_continue_read(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) {
+ if (tcp->incoming_buffer->count < (size_t)tcp->iov_size) {
+ grpc_resource_user_alloc_slices(
+ exec_ctx, &tcp->slice_allocator, tcp->slice_size,
+ (size_t)tcp->iov_size - tcp->incoming_buffer->count,
+ tcp->incoming_buffer);
+ } else {
+ tcp_do_read(exec_ctx, tcp);
+ }
+}
+
static void tcp_handle_read(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */,
grpc_error *error) {
grpc_tcp *tcp = (grpc_tcp *)arg;
@@ -259,6 +302,7 @@ static void tcp_handle_read(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */,
if (error != GRPC_ERROR_NONE) {
gpr_slice_buffer_reset_and_unref(tcp->incoming_buffer);
+ gpr_slice_buffer_reset_and_unref(&tcp->last_read_buffer);
call_read_cb(exec_ctx, tcp, GRPC_ERROR_REF(error));
TCP_UNREF(exec_ctx, tcp, "read");
} else {
@@ -469,6 +513,11 @@ static grpc_workqueue *tcp_get_workqueue(grpc_endpoint *ep) {
return grpc_fd_get_workqueue(tcp->em_fd);
}
+static grpc_resource_user *tcp_get_resource_user(grpc_endpoint *ep) {
+ grpc_tcp *tcp = (grpc_tcp *)ep;
+ return &tcp->resource_user;
+}
+
static const grpc_endpoint_vtable vtable = {tcp_read,
tcp_write,
tcp_get_workqueue,
@@ -476,10 +525,12 @@ static const grpc_endpoint_vtable vtable = {tcp_read,
tcp_add_to_pollset_set,
tcp_shutdown,
tcp_destroy,
+ tcp_get_resource_user,
tcp_get_peer};
-grpc_endpoint *grpc_tcp_create(grpc_fd *em_fd, size_t slice_size,
- const char *peer_string) {
+grpc_endpoint *grpc_tcp_create(grpc_fd *em_fd,
+ grpc_resource_quota *resource_quota,
+ size_t slice_size, const char *peer_string) {
grpc_tcp *tcp = (grpc_tcp *)gpr_malloc(sizeof(grpc_tcp));
tcp->base.vtable = &vtable;
tcp->peer_string = gpr_strdup(peer_string);
@@ -492,14 +543,20 @@ grpc_endpoint *grpc_tcp_create(grpc_fd *em_fd, size_t slice_size,
tcp->slice_size = slice_size;
tcp->iov_size = 1;
tcp->finished_edge = true;
- /* paired with unref in grpc_tcp_destroy */
- gpr_ref_init(&tcp->refcount, 1);
+ /* paired with unref in grpc_tcp_destroy, and with the shutdown for our
+ * resource_user */
+ gpr_ref_init(&tcp->refcount, 2);
+ gpr_atm_no_barrier_store(&tcp->shutdown_count, 0);
tcp->em_fd = em_fd;
tcp->read_closure.cb = tcp_handle_read;
tcp->read_closure.cb_arg = tcp;
tcp->write_closure.cb = tcp_handle_write;
tcp->write_closure.cb_arg = tcp;
gpr_slice_buffer_init(&tcp->last_read_buffer);
+ grpc_resource_user_init(&tcp->resource_user, resource_quota, peer_string);
+ grpc_resource_user_slice_allocator_init(&tcp->slice_allocator,
+ &tcp->resource_user,
+ tcp_read_allocation_done, tcp);
/* Tell network status tracker about new endpoint */
grpc_network_status_register_endpoint(&tcp->base);
@@ -514,10 +571,13 @@ int grpc_tcp_fd(grpc_endpoint *ep) {
void grpc_tcp_destroy_and_release_fd(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
int *fd, grpc_closure *done) {
+ grpc_network_status_unregister_endpoint(ep);
grpc_tcp *tcp = (grpc_tcp *)ep;
GPR_ASSERT(ep->vtable == &vtable);
tcp->release_fd = fd;
tcp->release_fd_cb = done;
+ tcp_maybe_shutdown_resource_user(exec_ctx, tcp);
+ gpr_slice_buffer_reset_and_unref(&tcp->last_read_buffer);
TCP_UNREF(exec_ctx, tcp, "destroy");
}
diff --git a/src/core/lib/iomgr/tcp_posix.h b/src/core/lib/iomgr/tcp_posix.h
index 99125836d6..1c0d13f96e 100644
--- a/src/core/lib/iomgr/tcp_posix.h
+++ b/src/core/lib/iomgr/tcp_posix.h
@@ -53,8 +53,8 @@ extern int grpc_tcp_trace;
/* Create a tcp endpoint given a file desciptor and a read slice size.
Takes ownership of fd. */
-grpc_endpoint *grpc_tcp_create(grpc_fd *fd, size_t read_slice_size,
- const char *peer_string);
+grpc_endpoint *grpc_tcp_create(grpc_fd *fd, grpc_resource_quota *resource_quota,
+ size_t read_slice_size, const char *peer_string);
/* Return the tcp endpoint's fd, or -1 if this is not available. Does not
release the fd.
diff --git a/src/core/lib/iomgr/tcp_server.h b/src/core/lib/iomgr/tcp_server.h
index 0c2a4f41da..6eba8c4057 100644
--- a/src/core/lib/iomgr/tcp_server.h
+++ b/src/core/lib/iomgr/tcp_server.h
@@ -61,7 +61,8 @@ typedef void (*grpc_tcp_server_cb)(grpc_exec_ctx *exec_ctx, void *arg,
/* Create a server, initially not bound to any ports. The caller owns one ref.
If shutdown_complete is not NULL, it will be used by
grpc_tcp_server_unref() when the ref count reaches zero. */
-grpc_error *grpc_tcp_server_create(grpc_closure *shutdown_complete,
+grpc_error *grpc_tcp_server_create(grpc_exec_ctx *exec_ctx,
+ grpc_closure *shutdown_complete,
const grpc_channel_args *args,
grpc_tcp_server **server);
diff --git a/src/core/lib/iomgr/tcp_server_posix.c b/src/core/lib/iomgr/tcp_server_posix.c
index 127f8595d1..b6fc1e4ca2 100644
--- a/src/core/lib/iomgr/tcp_server_posix.c
+++ b/src/core/lib/iomgr/tcp_server_posix.c
@@ -134,6 +134,8 @@ struct grpc_tcp_server {
/* next pollset to assign a channel to */
gpr_atm next_pollset_to_assign;
+
+ grpc_resource_quota *resource_quota;
};
static gpr_once check_init = GPR_ONCE_INIT;
@@ -150,23 +152,37 @@ static void init(void) {
#endif
}
-grpc_error *grpc_tcp_server_create(grpc_closure *shutdown_complete,
+grpc_error *grpc_tcp_server_create(grpc_exec_ctx *exec_ctx,
+ grpc_closure *shutdown_complete,
const grpc_channel_args *args,
grpc_tcp_server **server) {
gpr_once_init(&check_init, init);
grpc_tcp_server *s = gpr_malloc(sizeof(grpc_tcp_server));
s->so_reuseport = has_so_reuseport;
+ s->resource_quota = grpc_resource_quota_create(NULL);
for (size_t i = 0; i < (args == NULL ? 0 : args->num_args); i++) {
if (0 == strcmp(GRPC_ARG_ALLOW_REUSEPORT, args->args[i].key)) {
if (args->args[i].type == GRPC_ARG_INTEGER) {
s->so_reuseport =
has_so_reuseport && (args->args[i].value.integer != 0);
} else {
+ grpc_resource_quota_internal_unref(exec_ctx, s->resource_quota);
gpr_free(s);
return GRPC_ERROR_CREATE(GRPC_ARG_ALLOW_REUSEPORT
" must be an integer");
}
+ } else if (0 == strcmp(GRPC_ARG_RESOURCE_QUOTA, args->args[i].key)) {
+ if (args->args[i].type == GRPC_ARG_POINTER) {
+ grpc_resource_quota_internal_unref(exec_ctx, s->resource_quota);
+ s->resource_quota =
+ grpc_resource_quota_internal_ref(args->args[i].value.pointer.p);
+ } else {
+ grpc_resource_quota_internal_unref(exec_ctx, s->resource_quota);
+ gpr_free(s);
+ return GRPC_ERROR_CREATE(GRPC_ARG_RESOURCE_QUOTA
+ " must be a pointer to a buffer pool");
+ }
}
}
gpr_ref_init(&s->refs, 1);
@@ -203,6 +219,8 @@ static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
gpr_free(sp);
}
+ grpc_resource_quota_internal_unref(exec_ctx, s->resource_quota);
+
gpr_free(s);
}
@@ -419,7 +437,8 @@ static void on_read(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *err) {
sp->server->on_accept_cb(
exec_ctx, sp->server->on_accept_cb_arg,
- grpc_tcp_create(fdobj, GRPC_TCP_DEFAULT_READ_SLICE_SIZE, addr_str),
+ grpc_tcp_create(fdobj, sp->server->resource_quota,
+ GRPC_TCP_DEFAULT_READ_SLICE_SIZE, addr_str),
read_notifier_pollset, &acceptor);
gpr_free(name);
diff --git a/src/core/lib/security/credentials/google_default/google_default_credentials.c b/src/core/lib/security/credentials/google_default/google_default_credentials.c
index 312a3d4f90..cb5ba554b0 100644
--- a/src/core/lib/security/credentials/google_default/google_default_credentials.c
+++ b/src/core/lib/security/credentials/google_default/google_default_credentials.c
@@ -124,11 +124,14 @@ static int is_stack_running_on_compute_engine(void) {
grpc_httpcli_context_init(&context);
+ grpc_resource_quota *resource_quota =
+ grpc_resource_quota_create("google_default_credentials");
grpc_httpcli_get(
- &exec_ctx, &context, &detector.pollent, &request,
+ &exec_ctx, &context, &detector.pollent, resource_quota, &request,
gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), max_detection_delay),
grpc_closure_create(on_compute_engine_detection_http_response, &detector),
&detector.response);
+ grpc_resource_quota_internal_unref(&exec_ctx, resource_quota);
grpc_exec_ctx_flush(&exec_ctx);
diff --git a/src/core/lib/security/credentials/jwt/jwt_verifier.c b/src/core/lib/security/credentials/jwt/jwt_verifier.c
index 73eb2e3258..43eb642515 100644
--- a/src/core/lib/security/credentials/jwt/jwt_verifier.c
+++ b/src/core/lib/security/credentials/jwt/jwt_verifier.c
@@ -657,11 +657,17 @@ static void on_openid_config_retrieved(grpc_exec_ctx *exec_ctx, void *user_data,
*(req.host + (req.http.path - jwks_uri)) = '\0';
}
+ /* TODO(ctiller): Carry the resource_quota in ctx and share it with the host
+ channel. This would allow us to cancel an authentication query when under
+ extreme memory pressure. */
+ grpc_resource_quota *resource_quota =
+ grpc_resource_quota_create("jwt_verifier");
grpc_httpcli_get(
- exec_ctx, &ctx->verifier->http_ctx, &ctx->pollent, &req,
+ exec_ctx, &ctx->verifier->http_ctx, &ctx->pollent, resource_quota, &req,
gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), grpc_jwt_verifier_max_delay),
grpc_closure_create(on_keys_retrieved, ctx),
&ctx->responses[HTTP_RESPONSE_KEYS]);
+ grpc_resource_quota_internal_unref(exec_ctx, resource_quota);
grpc_json_destroy(json);
gpr_free(req.host);
return;
@@ -764,10 +770,16 @@ static void retrieve_key_and_verify(grpc_exec_ctx *exec_ctx,
rsp_idx = HTTP_RESPONSE_OPENID;
}
+ /* TODO(ctiller): Carry the resource_quota in ctx and share it with the host
+ channel. This would allow us to cancel an authentication query when under
+ extreme memory pressure. */
+ grpc_resource_quota *resource_quota =
+ grpc_resource_quota_create("jwt_verifier");
grpc_httpcli_get(
- exec_ctx, &ctx->verifier->http_ctx, &ctx->pollent, &req,
+ exec_ctx, &ctx->verifier->http_ctx, &ctx->pollent, resource_quota, &req,
gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), grpc_jwt_verifier_max_delay),
http_cb, &ctx->responses[rsp_idx]);
+ grpc_resource_quota_internal_unref(exec_ctx, resource_quota);
gpr_free(req.host);
gpr_free(req.http.path);
return;
diff --git a/src/core/lib/security/credentials/oauth2/oauth2_credentials.c b/src/core/lib/security/credentials/oauth2/oauth2_credentials.c
index c22ea5c468..d980577c46 100644
--- a/src/core/lib/security/credentials/oauth2/oauth2_credentials.c
+++ b/src/core/lib/security/credentials/oauth2/oauth2_credentials.c
@@ -307,9 +307,15 @@ static void compute_engine_fetch_oauth2(
request.http.path = GRPC_COMPUTE_ENGINE_METADATA_TOKEN_PATH;
request.http.hdr_count = 1;
request.http.hdrs = &header;
- grpc_httpcli_get(exec_ctx, httpcli_context, pollent, &request, deadline,
- grpc_closure_create(response_cb, metadata_req),
+ /* TODO(ctiller): Carry the resource_quota in ctx and share it with the host
+ channel. This would allow us to cancel an authentication query when under
+ extreme memory pressure. */
+ grpc_resource_quota *resource_quota =
+ grpc_resource_quota_create("oauth2_credentials");
+ grpc_httpcli_get(exec_ctx, httpcli_context, pollent, resource_quota, &request,
+ deadline, grpc_closure_create(response_cb, metadata_req),
&metadata_req->response);
+ grpc_resource_quota_internal_unref(exec_ctx, resource_quota);
}
grpc_call_credentials *grpc_google_compute_engine_credentials_create(
@@ -357,10 +363,16 @@ static void refresh_token_fetch_oauth2(
request.http.hdr_count = 1;
request.http.hdrs = &header;
request.handshaker = &grpc_httpcli_ssl;
- grpc_httpcli_post(exec_ctx, httpcli_context, pollent, &request, body,
- strlen(body), deadline,
+ /* TODO(ctiller): Carry the resource_quota in ctx and share it with the host
+ channel. This would allow us to cancel an authentication query when under
+ extreme memory pressure. */
+ grpc_resource_quota *resource_quota =
+ grpc_resource_quota_create("oauth2_credentials_refresh");
+ grpc_httpcli_post(exec_ctx, httpcli_context, pollent, resource_quota,
+ &request, body, strlen(body), deadline,
grpc_closure_create(response_cb, metadata_req),
&metadata_req->response);
+ grpc_resource_quota_internal_unref(exec_ctx, resource_quota);
gpr_free(body);
}
diff --git a/src/core/lib/security/transport/secure_endpoint.c b/src/core/lib/security/transport/secure_endpoint.c
index acb0113ea8..3924997d31 100644
--- a/src/core/lib/security/transport/secure_endpoint.c
+++ b/src/core/lib/security/transport/secure_endpoint.c
@@ -370,6 +370,12 @@ static grpc_workqueue *endpoint_get_workqueue(grpc_endpoint *secure_ep) {
return grpc_endpoint_get_workqueue(ep->wrapped_ep);
}
+static grpc_resource_user *endpoint_get_resource_user(
+ grpc_endpoint *secure_ep) {
+ secure_endpoint *ep = (secure_endpoint *)secure_ep;
+ return grpc_endpoint_get_resource_user(ep->wrapped_ep);
+}
+
static const grpc_endpoint_vtable vtable = {endpoint_read,
endpoint_write,
endpoint_get_workqueue,
@@ -377,6 +383,7 @@ static const grpc_endpoint_vtable vtable = {endpoint_read,
endpoint_add_to_pollset_set,
endpoint_shutdown,
endpoint_destroy,
+ endpoint_get_resource_user,
endpoint_get_peer};
grpc_endpoint *grpc_secure_endpoint_create(
diff --git a/src/core/lib/surface/call.c b/src/core/lib/surface/call.c
index 02a5de0857..6c25952c0a 100644
--- a/src/core/lib/surface/call.c
+++ b/src/core/lib/surface/call.c
@@ -1516,8 +1516,10 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
call, STATUS_FROM_API_OVERRIDE,
GRPC_MDSTR_REF(call->send_extra_metadata[1].md->value));
}
- set_status_code(call, STATUS_FROM_API_OVERRIDE,
- (uint32_t)op->data.send_status_from_server.status);
+ if (op->data.send_status_from_server.status != GRPC_STATUS_OK) {
+ set_status_code(call, STATUS_FROM_API_OVERRIDE,
+ (uint32_t)op->data.send_status_from_server.status);
+ }
if (!prepare_application_metadata(
call,
(int)op->data.send_status_from_server.trailing_metadata_count,
diff --git a/src/core/lib/surface/init.c b/src/core/lib/surface/init.c
index 8ca0643ba7..7903f57a68 100644
--- a/src/core/lib/surface/init.c
+++ b/src/core/lib/surface/init.c
@@ -52,6 +52,7 @@
#include "src/core/lib/iomgr/combiner.h"
#include "src/core/lib/iomgr/executor.h"
#include "src/core/lib/iomgr/iomgr.h"
+#include "src/core/lib/iomgr/resource_quota.h"
#include "src/core/lib/profiling/timers.h"
#include "src/core/lib/surface/api_trace.h"
#include "src/core/lib/surface/call.h"
@@ -191,6 +192,7 @@ void grpc_init(void) {
// Default timeout trace to 1
grpc_cq_event_timeout_trace = 1;
grpc_register_tracer("op_failure", &grpc_trace_operation_failures);
+ grpc_register_tracer("resource_quota", &grpc_resource_quota_trace);
#ifndef NDEBUG
grpc_register_tracer("pending_tags", &grpc_trace_pending_tags);
#endif
diff --git a/src/cpp/common/channel_arguments.cc b/src/cpp/common/channel_arguments.cc
index f297ae8587..d136d49c89 100644
--- a/src/cpp/common/channel_arguments.cc
+++ b/src/cpp/common/channel_arguments.cc
@@ -34,6 +34,7 @@
#include <sstream>
+#include <grpc++/resource_quota.h>
#include <grpc/impl/codegen/grpc_types.h>
#include <grpc/support/log.h>
#include "src/core/lib/channel/channel_args.h"
@@ -113,6 +114,13 @@ void ChannelArguments::SetUserAgentPrefix(
}
}
+void ChannelArguments::SetResourceQuota(
+ const grpc::ResourceQuota& resource_quota) {
+ SetPointerWithVtable(GRPC_ARG_RESOURCE_QUOTA,
+ resource_quota.c_resource_quota(),
+ grpc_resource_quota_arg_vtable());
+}
+
void ChannelArguments::SetInt(const grpc::string& key, int value) {
grpc_arg arg;
arg.type = GRPC_ARG_INTEGER;
@@ -127,12 +135,18 @@ void ChannelArguments::SetPointer(const grpc::string& key, void* value) {
static const grpc_arg_pointer_vtable vtable = {
&PointerVtableMembers::Copy, &PointerVtableMembers::Destroy,
&PointerVtableMembers::Compare};
+ SetPointerWithVtable(key, value, &vtable);
+}
+
+void ChannelArguments::SetPointerWithVtable(
+ const grpc::string& key, void* value,
+ const grpc_arg_pointer_vtable* vtable) {
grpc_arg arg;
arg.type = GRPC_ARG_POINTER;
strings_.push_back(key);
arg.key = const_cast<char*>(strings_.back().c_str());
arg.value.pointer.p = value;
- arg.value.pointer.vtable = &vtable;
+ arg.value.pointer.vtable = vtable;
args_.push_back(arg);
}
diff --git a/src/cpp/common/resource_quota_cc.cc b/src/cpp/common/resource_quota_cc.cc
new file mode 100644
index 0000000000..335896ab91
--- /dev/null
+++ b/src/cpp/common/resource_quota_cc.cc
@@ -0,0 +1,51 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc++/resource_quota.h>
+#include <grpc/grpc.h>
+
+namespace grpc {
+
+ResourceQuota::ResourceQuota() : impl_(grpc_resource_quota_create(nullptr)) {}
+
+ResourceQuota::ResourceQuota(const grpc::string& name)
+ : impl_(grpc_resource_quota_create(name.c_str())) {}
+
+ResourceQuota::~ResourceQuota() { grpc_resource_quota_unref(impl_); }
+
+ResourceQuota& ResourceQuota::Resize(size_t new_size) {
+ grpc_resource_quota_resize(impl_, new_size);
+ return *this;
+}
+
+} // namespace grpc
diff --git a/src/cpp/server/server_builder.cc b/src/cpp/server/server_builder.cc
index 2980b16c56..953a4337ec 100644
--- a/src/cpp/server/server_builder.cc
+++ b/src/cpp/server/server_builder.cc
@@ -34,6 +34,7 @@
#include <grpc++/server_builder.h>
#include <grpc++/impl/service_type.h>
+#include <grpc++/resource_quota.h>
#include <grpc++/server.h>
#include <grpc/support/log.h>
#include <grpc/support/useful.h>
@@ -54,6 +55,7 @@ static void do_plugin_list_init(void) {
ServerBuilder::ServerBuilder()
: max_receive_message_size_(-1),
max_send_message_size_(-1),
+ resource_quota_(nullptr),
generic_service_(nullptr) {
gpr_once_init(&once_init_plugin_list, do_plugin_list_init);
for (auto it = g_plugin_factory_list->begin();
@@ -70,6 +72,12 @@ ServerBuilder::ServerBuilder()
sizeof(maybe_default_compression_algorithm_));
}
+ServerBuilder::~ServerBuilder() {
+ if (resource_quota_ != nullptr) {
+ grpc_resource_quota_unref(resource_quota_);
+ }
+}
+
std::unique_ptr<ServerCompletionQueue> ServerBuilder::AddCompletionQueue(
bool is_frequently_polled) {
ServerCompletionQueue* cq = new ServerCompletionQueue(is_frequently_polled);
@@ -130,6 +138,16 @@ ServerBuilder& ServerBuilder::SetDefaultCompressionAlgorithm(
return *this;
}
+ServerBuilder& ServerBuilder::SetResourceQuota(
+ const grpc::ResourceQuota& resource_quota) {
+ if (resource_quota_ != nullptr) {
+ grpc_resource_quota_unref(resource_quota_);
+ }
+ resource_quota_ = resource_quota.c_resource_quota();
+ grpc_resource_quota_ref(resource_quota_);
+ return *this;
+}
+
ServerBuilder& ServerBuilder::AddListeningPort(
const grpc::string& addr, std::shared_ptr<ServerCredentials> creds,
int* selected_port) {
@@ -178,6 +196,10 @@ std::unique_ptr<Server> ServerBuilder::BuildAndStart() {
args.SetInt(GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM,
maybe_default_compression_algorithm_.algorithm);
}
+ if (resource_quota_ != nullptr) {
+ args.SetPointerWithVtable(GRPC_ARG_RESOURCE_QUOTA, resource_quota_,
+ grpc_resource_quota_arg_vtable());
+ }
std::unique_ptr<Server> server(new Server(thread_pool.release(), true,
max_receive_message_size_, &args));
ServerInitializer* initializer = server->initializer();
diff --git a/src/proto/grpc/testing/control.proto b/src/proto/grpc/testing/control.proto
index ece6910815..918f5fa3e3 100644
--- a/src/proto/grpc/testing/control.proto
+++ b/src/proto/grpc/testing/control.proto
@@ -137,6 +137,11 @@ message ServerConfig {
// If we use an OTHER_SERVER client_type, this string gives more detail
string other_server_api = 11;
+
+ // c++-only options (for now) --------------------------------
+
+ // Buffer pool size (no buffer pool specified if unset)
+ int32 resource_quota_size = 1001;
}
message ServerArgs {
@@ -213,6 +218,10 @@ message ScenarioResultSummary
double latency_95 = 9;
double latency_99 = 10;
double latency_999 = 11;
+
+ // Number of requests that succeeded/failed
+ double successful_requests_per_second = 12;
+ double failed_requests_per_second = 13;
}
// Results of a single benchmark scenario.
@@ -232,4 +241,6 @@ message ScenarioResult {
// Information on success or failure of each worker
repeated bool client_success = 7;
repeated bool server_success = 8;
+ // Number of failed requests (one row per status code seen)
+ repeated RequestResultCount request_results = 9;
}
diff --git a/src/proto/grpc/testing/stats.proto b/src/proto/grpc/testing/stats.proto
index f9d116110b..d40d714801 100644
--- a/src/proto/grpc/testing/stats.proto
+++ b/src/proto/grpc/testing/stats.proto
@@ -59,6 +59,11 @@ message HistogramData {
double count = 6;
}
+message RequestResultCount {
+ int32 status_code = 1;
+ int64 count = 2;
+}
+
message ClientStats {
// Latency histogram. Data points are in nanoseconds.
HistogramData latencies = 1;
@@ -67,4 +72,7 @@ message ClientStats {
double time_elapsed = 2;
double time_user = 3;
double time_system = 4;
+
+ // Number of failed requests (one row per status code seen)
+ repeated RequestResultCount request_results = 5;
}
diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
index 7ffe0f558a..1ad423909f 100644
--- a/src/python/grpcio/grpc_core_dependencies.py
+++ b/src/python/grpcio/grpc_core_dependencies.py
@@ -122,6 +122,7 @@ CORE_SOURCE_FILES = [
'src/core/lib/iomgr/resolve_address_posix.c',
'src/core/lib/iomgr/resolve_address_uv.c',
'src/core/lib/iomgr/resolve_address_windows.c',
+ 'src/core/lib/iomgr/resource_quota.c',
'src/core/lib/iomgr/sockaddr_utils.c',
'src/core/lib/iomgr/socket_utils_common_posix.c',
'src/core/lib/iomgr/socket_utils_linux.c',
diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.c b/src/ruby/ext/grpc/rb_grpc_imports.generated.c
index a6cad0db1a..fd73cc7970 100644
--- a/src/ruby/ext/grpc/rb_grpc_imports.generated.c
+++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.c
@@ -132,6 +132,11 @@ grpc_header_key_is_legal_type grpc_header_key_is_legal_import;
grpc_header_nonbin_value_is_legal_type grpc_header_nonbin_value_is_legal_import;
grpc_is_binary_header_type grpc_is_binary_header_import;
grpc_call_error_to_string_type grpc_call_error_to_string_import;
+grpc_resource_quota_create_type grpc_resource_quota_create_import;
+grpc_resource_quota_ref_type grpc_resource_quota_ref_import;
+grpc_resource_quota_unref_type grpc_resource_quota_unref_import;
+grpc_resource_quota_resize_type grpc_resource_quota_resize_import;
+grpc_resource_quota_arg_vtable_type grpc_resource_quota_arg_vtable_import;
grpc_insecure_channel_create_from_fd_type grpc_insecure_channel_create_from_fd_import;
grpc_server_add_insecure_channel_from_fd_type grpc_server_add_insecure_channel_from_fd_import;
grpc_use_signal_type grpc_use_signal_import;
@@ -401,6 +406,11 @@ void grpc_rb_load_imports(HMODULE library) {
grpc_header_nonbin_value_is_legal_import = (grpc_header_nonbin_value_is_legal_type) GetProcAddress(library, "grpc_header_nonbin_value_is_legal");
grpc_is_binary_header_import = (grpc_is_binary_header_type) GetProcAddress(library, "grpc_is_binary_header");
grpc_call_error_to_string_import = (grpc_call_error_to_string_type) GetProcAddress(library, "grpc_call_error_to_string");
+ grpc_resource_quota_create_import = (grpc_resource_quota_create_type) GetProcAddress(library, "grpc_resource_quota_create");
+ grpc_resource_quota_ref_import = (grpc_resource_quota_ref_type) GetProcAddress(library, "grpc_resource_quota_ref");
+ grpc_resource_quota_unref_import = (grpc_resource_quota_unref_type) GetProcAddress(library, "grpc_resource_quota_unref");
+ grpc_resource_quota_resize_import = (grpc_resource_quota_resize_type) GetProcAddress(library, "grpc_resource_quota_resize");
+ grpc_resource_quota_arg_vtable_import = (grpc_resource_quota_arg_vtable_type) GetProcAddress(library, "grpc_resource_quota_arg_vtable");
grpc_insecure_channel_create_from_fd_import = (grpc_insecure_channel_create_from_fd_type) GetProcAddress(library, "grpc_insecure_channel_create_from_fd");
grpc_server_add_insecure_channel_from_fd_import = (grpc_server_add_insecure_channel_from_fd_type) GetProcAddress(library, "grpc_server_add_insecure_channel_from_fd");
grpc_use_signal_import = (grpc_use_signal_type) GetProcAddress(library, "grpc_use_signal");
diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.h b/src/ruby/ext/grpc/rb_grpc_imports.generated.h
index 00a67b0b2c..c2244150f2 100644
--- a/src/ruby/ext/grpc/rb_grpc_imports.generated.h
+++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.h
@@ -347,6 +347,21 @@ extern grpc_is_binary_header_type grpc_is_binary_header_import;
typedef const char *(*grpc_call_error_to_string_type)(grpc_call_error error);
extern grpc_call_error_to_string_type grpc_call_error_to_string_import;
#define grpc_call_error_to_string grpc_call_error_to_string_import
+typedef grpc_resource_quota *(*grpc_resource_quota_create_type)(const char *trace_name);
+extern grpc_resource_quota_create_type grpc_resource_quota_create_import;
+#define grpc_resource_quota_create grpc_resource_quota_create_import
+typedef void(*grpc_resource_quota_ref_type)(grpc_resource_quota *resource_quota);
+extern grpc_resource_quota_ref_type grpc_resource_quota_ref_import;
+#define grpc_resource_quota_ref grpc_resource_quota_ref_import
+typedef void(*grpc_resource_quota_unref_type)(grpc_resource_quota *resource_quota);
+extern grpc_resource_quota_unref_type grpc_resource_quota_unref_import;
+#define grpc_resource_quota_unref grpc_resource_quota_unref_import
+typedef void(*grpc_resource_quota_resize_type)(grpc_resource_quota *resource_quota, size_t new_size);
+extern grpc_resource_quota_resize_type grpc_resource_quota_resize_import;
+#define grpc_resource_quota_resize grpc_resource_quota_resize_import
+typedef const grpc_arg_pointer_vtable *(*grpc_resource_quota_arg_vtable_type)(void);
+extern grpc_resource_quota_arg_vtable_type grpc_resource_quota_arg_vtable_import;
+#define grpc_resource_quota_arg_vtable grpc_resource_quota_arg_vtable_import
typedef grpc_channel *(*grpc_insecure_channel_create_from_fd_type)(const char *target, int fd, const grpc_channel_args *args);
extern grpc_insecure_channel_create_from_fd_type grpc_insecure_channel_create_from_fd_import;
#define grpc_insecure_channel_create_from_fd grpc_insecure_channel_create_from_fd_import
diff --git a/test/core/bad_client/bad_client.c b/test/core/bad_client/bad_client.c
index be88d4a69a..a9638500b7 100644
--- a/test/core/bad_client/bad_client.c
+++ b/test/core/bad_client/bad_client.c
@@ -114,7 +114,10 @@ void grpc_run_bad_client_test(
grpc_init();
/* Create endpoints */
- sfd = grpc_iomgr_create_endpoint_pair("fixture", 65536);
+ grpc_resource_quota *resource_quota =
+ grpc_resource_quota_create("bad_client_test");
+ sfd = grpc_iomgr_create_endpoint_pair("fixture", resource_quota, 65536);
+ grpc_resource_quota_internal_unref(&exec_ctx, resource_quota);
/* Create server, completion events */
a.server = grpc_server_create(NULL, NULL);
diff --git a/test/core/end2end/end2end_nosec_tests.c b/test/core/end2end/end2end_nosec_tests.c
index a630262197..caaa97c215 100644
--- a/test/core/end2end/end2end_nosec_tests.c
+++ b/test/core/end2end/end2end_nosec_tests.c
@@ -111,6 +111,8 @@ extern void request_with_flags(grpc_end2end_test_config config);
extern void request_with_flags_pre_init(void);
extern void request_with_payload(grpc_end2end_test_config config);
extern void request_with_payload_pre_init(void);
+extern void resource_quota_server(grpc_end2end_test_config config);
+extern void resource_quota_server_pre_init(void);
extern void server_finishes_request(grpc_end2end_test_config config);
extern void server_finishes_request_pre_init(void);
extern void shutdown_finishes_calls(grpc_end2end_test_config config);
@@ -167,6 +169,7 @@ void grpc_end2end_tests_pre_init(void) {
registered_call_pre_init();
request_with_flags_pre_init();
request_with_payload_pre_init();
+ resource_quota_server_pre_init();
server_finishes_request_pre_init();
shutdown_finishes_calls_pre_init();
shutdown_finishes_tags_pre_init();
@@ -219,6 +222,7 @@ void grpc_end2end_tests(int argc, char **argv,
registered_call(config);
request_with_flags(config);
request_with_payload(config);
+ resource_quota_server(config);
server_finishes_request(config);
shutdown_finishes_calls(config);
shutdown_finishes_tags(config);
@@ -368,6 +372,10 @@ void grpc_end2end_tests(int argc, char **argv,
request_with_payload(config);
continue;
}
+ if (0 == strcmp("resource_quota_server", argv[i])) {
+ resource_quota_server(config);
+ continue;
+ }
if (0 == strcmp("server_finishes_request", argv[i])) {
server_finishes_request(config);
continue;
diff --git a/test/core/end2end/end2end_tests.c b/test/core/end2end/end2end_tests.c
index 925872a71f..6d17e686e6 100644
--- a/test/core/end2end/end2end_tests.c
+++ b/test/core/end2end/end2end_tests.c
@@ -113,6 +113,8 @@ extern void request_with_flags(grpc_end2end_test_config config);
extern void request_with_flags_pre_init(void);
extern void request_with_payload(grpc_end2end_test_config config);
extern void request_with_payload_pre_init(void);
+extern void resource_quota_server(grpc_end2end_test_config config);
+extern void resource_quota_server_pre_init(void);
extern void server_finishes_request(grpc_end2end_test_config config);
extern void server_finishes_request_pre_init(void);
extern void shutdown_finishes_calls(grpc_end2end_test_config config);
@@ -170,6 +172,7 @@ void grpc_end2end_tests_pre_init(void) {
registered_call_pre_init();
request_with_flags_pre_init();
request_with_payload_pre_init();
+ resource_quota_server_pre_init();
server_finishes_request_pre_init();
shutdown_finishes_calls_pre_init();
shutdown_finishes_tags_pre_init();
@@ -223,6 +226,7 @@ void grpc_end2end_tests(int argc, char **argv,
registered_call(config);
request_with_flags(config);
request_with_payload(config);
+ resource_quota_server(config);
server_finishes_request(config);
shutdown_finishes_calls(config);
shutdown_finishes_tags(config);
@@ -376,6 +380,10 @@ void grpc_end2end_tests(int argc, char **argv,
request_with_payload(config);
continue;
}
+ if (0 == strcmp("resource_quota_server", argv[i])) {
+ resource_quota_server(config);
+ continue;
+ }
if (0 == strcmp("server_finishes_request", argv[i])) {
server_finishes_request(config);
continue;
diff --git a/test/core/end2end/fixtures/h2_sockpair+trace.c b/test/core/end2end/fixtures/h2_sockpair+trace.c
index 15b045c33c..a358edf321 100644
--- a/test/core/end2end/fixtures/h2_sockpair+trace.c
+++ b/test/core/end2end/fixtures/h2_sockpair+trace.c
@@ -96,7 +96,9 @@ static grpc_end2end_test_fixture chttp2_create_fixture_socketpair(
f.fixture_data = sfd;
f.cq = grpc_completion_queue_create(NULL);
- *sfd = grpc_iomgr_create_endpoint_pair("fixture", 65536);
+ grpc_resource_quota *resource_quota = grpc_resource_quota_create("fixture");
+ *sfd = grpc_iomgr_create_endpoint_pair("fixture", resource_quota, 65536);
+ grpc_resource_quota_unref(resource_quota);
return f;
}
diff --git a/test/core/end2end/fixtures/h2_sockpair.c b/test/core/end2end/fixtures/h2_sockpair.c
index 87091f77a3..8f7083af59 100644
--- a/test/core/end2end/fixtures/h2_sockpair.c
+++ b/test/core/end2end/fixtures/h2_sockpair.c
@@ -90,7 +90,9 @@ static grpc_end2end_test_fixture chttp2_create_fixture_socketpair(
f.fixture_data = sfd;
f.cq = grpc_completion_queue_create(NULL);
- *sfd = grpc_iomgr_create_endpoint_pair("fixture", 65536);
+ grpc_resource_quota *resource_quota = grpc_resource_quota_create("fixture");
+ *sfd = grpc_iomgr_create_endpoint_pair("fixture", resource_quota, 65536);
+ grpc_resource_quota_unref(resource_quota);
return f;
}
diff --git a/test/core/end2end/fixtures/h2_sockpair_1byte.c b/test/core/end2end/fixtures/h2_sockpair_1byte.c
index 7d0a14cd63..b3d9924c12 100644
--- a/test/core/end2end/fixtures/h2_sockpair_1byte.c
+++ b/test/core/end2end/fixtures/h2_sockpair_1byte.c
@@ -90,7 +90,9 @@ static grpc_end2end_test_fixture chttp2_create_fixture_socketpair(
f.fixture_data = sfd;
f.cq = grpc_completion_queue_create(NULL);
- *sfd = grpc_iomgr_create_endpoint_pair("fixture", 1);
+ grpc_resource_quota *resource_quota = grpc_resource_quota_create("fixture");
+ *sfd = grpc_iomgr_create_endpoint_pair("fixture", resource_quota, 1);
+ grpc_resource_quota_unref(resource_quota);
return f;
}
diff --git a/test/core/end2end/fixtures/http_proxy.c b/test/core/end2end/fixtures/http_proxy.c
index b8f046c7df..630f47ef0e 100644
--- a/test/core/end2end/fixtures/http_proxy.c
+++ b/test/core/end2end/fixtures/http_proxy.c
@@ -359,7 +359,7 @@ static void on_read_request_done(grpc_exec_ctx* exec_ctx, void* arg,
const gpr_timespec deadline = gpr_time_add(
gpr_now(GPR_CLOCK_MONOTONIC), gpr_time_from_seconds(10, GPR_TIMESPAN));
grpc_tcp_client_connect(exec_ctx, &conn->on_server_connect_done,
- &conn->server_endpoint, conn->pollset_set,
+ &conn->server_endpoint, conn->pollset_set, NULL,
&resolved_addresses->addrs[0], deadline);
grpc_resolved_addresses_destroy(resolved_addresses);
}
@@ -418,7 +418,8 @@ static void thread_main(void* arg) {
grpc_exec_ctx_finish(&exec_ctx);
}
-grpc_end2end_http_proxy* grpc_end2end_http_proxy_create() {
+grpc_end2end_http_proxy* grpc_end2end_http_proxy_create(void) {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
grpc_end2end_http_proxy* proxy = gpr_malloc(sizeof(*proxy));
memset(proxy, 0, sizeof(*proxy));
// Construct proxy address.
@@ -427,8 +428,8 @@ grpc_end2end_http_proxy* grpc_end2end_http_proxy_create() {
gpr_log(GPR_INFO, "Proxy address: %s", proxy->proxy_name);
// Create TCP server.
proxy->channel_args = grpc_channel_args_copy(NULL);
- grpc_error* error =
- grpc_tcp_server_create(NULL, proxy->channel_args, &proxy->server);
+ grpc_error* error = grpc_tcp_server_create(
+ &exec_ctx, NULL, proxy->channel_args, &proxy->server);
GPR_ASSERT(error == GRPC_ERROR_NONE);
// Bind to port.
grpc_resolved_address resolved_addr;
@@ -443,7 +444,6 @@ grpc_end2end_http_proxy* grpc_end2end_http_proxy_create() {
// Start server.
proxy->pollset = gpr_malloc(grpc_pollset_size());
grpc_pollset_init(proxy->pollset, &proxy->mu);
- grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
grpc_tcp_server_start(&exec_ctx, proxy->server, &proxy->pollset, 1, on_accept,
proxy);
grpc_exec_ctx_finish(&exec_ctx);
diff --git a/test/core/end2end/fuzzers/api_fuzzer.c b/test/core/end2end/fuzzers/api_fuzzer.c
index 4e19b76014..659f5cf5cb 100644
--- a/test/core/end2end/fuzzers/api_fuzzer.c
+++ b/test/core/end2end/fuzzers/api_fuzzer.c
@@ -173,6 +173,7 @@ static bool is_eof(input_stream *inp) { return inp->cur == inp->end; }
static gpr_timespec g_now;
static grpc_server *g_server;
static grpc_channel *g_channel;
+static grpc_resource_quota *g_resource_quota;
extern gpr_timespec (*gpr_now_impl)(gpr_clock_type clock_type);
@@ -231,8 +232,8 @@ void my_resolve_address(grpc_exec_ctx *exec_ctx, const char *addr,
// defined in tcp_client_posix.c
extern void (*grpc_tcp_client_connect_impl)(
grpc_exec_ctx *exec_ctx, grpc_closure *closure, grpc_endpoint **ep,
- grpc_pollset_set *interested_parties, const grpc_resolved_address *addr,
- gpr_timespec deadline);
+ grpc_pollset_set *interested_parties, const grpc_channel_args *channel_args,
+ const grpc_resolved_address *addr, gpr_timespec deadline);
static void sched_connect(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
grpc_endpoint **ep, gpr_timespec deadline);
@@ -252,7 +253,7 @@ static void do_connect(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
} else if (g_server != NULL) {
grpc_endpoint *client;
grpc_endpoint *server;
- grpc_passthru_endpoint_create(&client, &server);
+ grpc_passthru_endpoint_create(&client, &server, g_resource_quota);
*fc->ep = client;
grpc_transport *transport =
@@ -289,6 +290,7 @@ static void sched_connect(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
static void my_tcp_client_connect(grpc_exec_ctx *exec_ctx,
grpc_closure *closure, grpc_endpoint **ep,
grpc_pollset_set *interested_parties,
+ const grpc_channel_args *channel_args,
const grpc_resolved_address *addr,
gpr_timespec deadline) {
sched_connect(exec_ctx, closure, ep, deadline);
@@ -520,6 +522,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
int pending_pings = 0;
g_active_call = new_call(NULL, ROOT);
+ g_resource_quota = grpc_resource_quota_create("api_fuzzer");
grpc_completion_queue *cq = grpc_completion_queue_create(NULL);
@@ -939,6 +942,11 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
}
break;
}
+ // resize the buffer pool
+ case 21: {
+ grpc_resource_quota_resize(g_resource_quota, read_uint22(&inp));
+ break;
+ }
}
}
@@ -954,6 +962,8 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
.type == GRPC_QUEUE_SHUTDOWN);
grpc_completion_queue_destroy(cq);
+ grpc_resource_quota_unref(g_resource_quota);
+
grpc_shutdown();
return 0;
}
diff --git a/test/core/end2end/fuzzers/client_fuzzer.c b/test/core/end2end/fuzzers/client_fuzzer.c
index 00e650a30b..d104fe55e5 100644
--- a/test/core/end2end/fuzzers/client_fuzzer.c
+++ b/test/core/end2end/fuzzers/client_fuzzer.c
@@ -58,7 +58,11 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
grpc_init();
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
- grpc_endpoint *mock_endpoint = grpc_mock_endpoint_create(discard_write);
+ grpc_resource_quota *resource_quota =
+ grpc_resource_quota_create("client_fuzzer");
+ grpc_endpoint *mock_endpoint =
+ grpc_mock_endpoint_create(discard_write, resource_quota);
+ grpc_resource_quota_internal_unref(&exec_ctx, resource_quota);
grpc_completion_queue *cq = grpc_completion_queue_create(NULL);
grpc_transport *transport =
diff --git a/test/core/end2end/fuzzers/server_fuzzer.c b/test/core/end2end/fuzzers/server_fuzzer.c
index 79eaad70c5..ae4c8e658d 100644
--- a/test/core/end2end/fuzzers/server_fuzzer.c
+++ b/test/core/end2end/fuzzers/server_fuzzer.c
@@ -56,7 +56,11 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
grpc_init();
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
- grpc_endpoint *mock_endpoint = grpc_mock_endpoint_create(discard_write);
+ grpc_resource_quota *resource_quota =
+ grpc_resource_quota_create("server_fuzzer");
+ grpc_endpoint *mock_endpoint =
+ grpc_mock_endpoint_create(discard_write, resource_quota);
+ grpc_resource_quota_internal_unref(&exec_ctx, resource_quota);
grpc_mock_endpoint_put_read(
&exec_ctx, mock_endpoint,
gpr_slice_from_copied_buffer((const char *)data, size));
diff --git a/test/core/end2end/gen_build_yaml.py b/test/core/end2end/gen_build_yaml.py
index 0bbf10d475..bdb3874c21 100755
--- a/test/core/end2end/gen_build_yaml.py
+++ b/test/core/end2end/gen_build_yaml.py
@@ -39,9 +39,9 @@ import hashlib
FixtureOptions = collections.namedtuple(
'FixtureOptions',
- 'fullstack includes_proxy dns_resolver secure platforms ci_mac tracing exclude_configs exclude_iomgrs')
+ 'fullstack includes_proxy dns_resolver secure platforms ci_mac tracing exclude_configs exclude_iomgrs large_writes')
default_unsecure_fixture_options = FixtureOptions(
- True, False, True, False, ['windows', 'linux', 'mac', 'posix'], True, False, [], [])
+ True, False, True, False, ['windows', 'linux', 'mac', 'posix'], True, False, [], [], True)
socketpair_unsecure_fixture_options = default_unsecure_fixture_options._replace(fullstack=False, dns_resolver=False)
default_secure_fixture_options = default_unsecure_fixture_options._replace(secure=True)
uds_fixture_options = default_unsecure_fixture_options._replace(dns_resolver=False, platforms=['linux', 'mac', 'posix'], exclude_iomgrs=['uv'])
@@ -69,11 +69,12 @@ END2END_FIXTURES = {
'h2_proxy': default_unsecure_fixture_options._replace(
includes_proxy=True, ci_mac=False, exclude_iomgrs=['uv']),
'h2_sockpair_1byte': socketpair_unsecure_fixture_options._replace(
- ci_mac=False, exclude_configs=['msan'], exclude_iomgrs=['uv']),
+ ci_mac=False, exclude_configs=['msan'], large_writes=False,
+ exclude_iomgrs=['uv']),
'h2_sockpair': socketpair_unsecure_fixture_options._replace(
ci_mac=False, exclude_iomgrs=['uv']),
'h2_sockpair+trace': socketpair_unsecure_fixture_options._replace(
- ci_mac=False, tracing=True, exclude_iomgrs=['uv']),
+ ci_mac=False, tracing=True, large_writes=False, exclude_iomgrs=['uv']),
'h2_ssl': default_secure_fixture_options,
'h2_ssl_cert': default_secure_fixture_options,
'h2_ssl_proxy': default_secure_fixture_options._replace(
@@ -83,8 +84,8 @@ END2END_FIXTURES = {
TestOptions = collections.namedtuple(
'TestOptions',
- 'needs_fullstack needs_dns proxyable secure traceable cpu_cost exclude_iomgrs')
-default_test_options = TestOptions(False, False, True, False, True, 1.0, [])
+ 'needs_fullstack needs_dns proxyable secure traceable cpu_cost exclude_iomgrs large_writes flaky')
+default_test_options = TestOptions(False, False, True, False, True, 1.0, [], False, False)
connectivity_test_options = default_test_options._replace(needs_fullstack=True)
LOWCPU = 0.1
@@ -93,6 +94,8 @@ LOWCPU = 0.1
END2END_TESTS = {
'bad_hostname': default_test_options,
'binary_metadata': default_test_options,
+ 'resource_quota_server': default_test_options._replace(large_writes=True,
+ proxyable=False),
'call_creds': default_test_options._replace(secure=True),
'cancel_after_accept': default_test_options._replace(cpu_cost=LOWCPU),
'cancel_after_client_done': default_test_options,
@@ -105,7 +108,7 @@ END2END_TESTS = {
proxyable=False, cpu_cost=LOWCPU, exclude_iomgrs=['uv']),
'default_host': default_test_options._replace(needs_fullstack=True,
needs_dns=True),
- 'disappearing_server': connectivity_test_options,
+ 'disappearing_server': connectivity_test_options._replace(flaky=True),
'empty_batch': default_test_options,
'filter_causes_close': default_test_options,
'filter_call_init_fails': default_test_options,
@@ -155,6 +158,9 @@ def compatible(f, t):
if not END2END_TESTS[t].traceable:
if END2END_FIXTURES[f].tracing:
return False
+ if END2END_TESTS[t].large_writes:
+ if not END2END_FIXTURES[f].large_writes:
+ return False
return True
@@ -257,7 +263,7 @@ def main():
'ci_platforms': (END2END_FIXTURES[f].platforms
if END2END_FIXTURES[f].ci_mac else without(
END2END_FIXTURES[f].platforms, 'mac')),
- 'flaky': False,
+ 'flaky': END2END_TESTS[t].flaky,
'language': 'c',
'cpu_cost': END2END_TESTS[t].cpu_cost,
}
@@ -274,7 +280,7 @@ def main():
'ci_platforms': (END2END_FIXTURES[f].platforms
if END2END_FIXTURES[f].ci_mac else without(
END2END_FIXTURES[f].platforms, 'mac')),
- 'flaky': False,
+ 'flaky': END2END_TESTS[t].flaky,
'language': 'c',
'cpu_cost': END2END_TESTS[t].cpu_cost,
}
diff --git a/test/core/end2end/tests/max_message_length.c b/test/core/end2end/tests/max_message_length.c
index e698987a0a..449a581d23 100644
--- a/test/core/end2end/tests/max_message_length.c
+++ b/test/core/end2end/tests/max_message_length.c
@@ -402,7 +402,6 @@ static void test_max_message_length_on_response(grpc_end2end_test_config config,
GPR_ASSERT(0 == strcmp(call_details.method, "/service/method"));
GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr:1234"));
- GPR_ASSERT(was_cancelled == 0);
GPR_ASSERT(status == GRPC_STATUS_INVALID_ARGUMENT);
GPR_ASSERT(strcmp(details,
diff --git a/test/core/end2end/tests/network_status_change.c b/test/core/end2end/tests/network_status_change.c
index 8d6b8f8784..fa711bb0b6 100644
--- a/test/core/end2end/tests/network_status_change.c
+++ b/test/core/end2end/tests/network_status_change.c
@@ -213,7 +213,6 @@ static void test_invoke_network_status_change(grpc_end2end_test_config config) {
GPR_ASSERT(status == GRPC_STATUS_UNAVAILABLE);
GPR_ASSERT(0 == strcmp(call_details.method, "/foo"));
GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr"));
- GPR_ASSERT(was_cancelled == 0);
gpr_free(details);
grpc_metadata_array_destroy(&initial_metadata_recv);
diff --git a/test/core/end2end/tests/resource_quota_server.c b/test/core/end2end/tests/resource_quota_server.c
new file mode 100644
index 0000000000..76374d16a5
--- /dev/null
+++ b/test/core/end2end/tests/resource_quota_server.c
@@ -0,0 +1,359 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "test/core/end2end/end2end_tests.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/byte_buffer.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/time.h>
+#include <grpc/support/useful.h>
+#include "test/core/end2end/cq_verifier.h"
+
+static void *tag(intptr_t t) { return (void *)t; }
+
+static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
+ const char *test_name,
+ grpc_channel_args *client_args,
+ grpc_channel_args *server_args) {
+ grpc_end2end_test_fixture f;
+ gpr_log(GPR_INFO, "%s/%s", test_name, config.name);
+ f = config.create_fixture(client_args, server_args);
+ config.init_server(&f, server_args);
+ config.init_client(&f, client_args, NULL);
+ return f;
+}
+
+static gpr_timespec n_seconds_time(int n) {
+ return GRPC_TIMEOUT_SECONDS_TO_DEADLINE(n);
+}
+
+static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+
+static void drain_cq(grpc_completion_queue *cq) {
+ grpc_event ev;
+ do {
+ ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+ } while (ev.type != GRPC_QUEUE_SHUTDOWN);
+}
+
+static void shutdown_server(grpc_end2end_test_fixture *f) {
+ if (!f->server) return;
+ grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
+ GPR_ASSERT(grpc_completion_queue_pluck(
+ f->cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5), NULL)
+ .type == GRPC_OP_COMPLETE);
+ grpc_server_destroy(f->server);
+ f->server = NULL;
+}
+
+static void shutdown_client(grpc_end2end_test_fixture *f) {
+ if (!f->client) return;
+ grpc_channel_destroy(f->client);
+ f->client = NULL;
+}
+
+static void end_test(grpc_end2end_test_fixture *f) {
+ shutdown_server(f);
+ shutdown_client(f);
+
+ grpc_completion_queue_shutdown(f->cq);
+ drain_cq(f->cq);
+ grpc_completion_queue_destroy(f->cq);
+}
+
+/* Creates and returns a gpr_slice containing random alphanumeric characters. */
+static gpr_slice generate_random_slice() {
+ size_t i;
+ static const char chars[] = "abcdefghijklmnopqrstuvwxyz1234567890";
+ char output[1024 * 1024];
+ for (i = 0; i < GPR_ARRAY_SIZE(output) - 1; ++i) {
+ output[i] = chars[rand() % (int)(sizeof(chars) - 1)];
+ }
+ output[GPR_ARRAY_SIZE(output) - 1] = '\0';
+ return gpr_slice_from_copied_string(output);
+}
+
+void resource_quota_server(grpc_end2end_test_config config) {
+ grpc_resource_quota *resource_quota =
+ grpc_resource_quota_create("test_server");
+ grpc_resource_quota_resize(resource_quota, 5 * 1024 * 1024);
+
+#define NUM_CALLS 100
+#define CLIENT_BASE_TAG 1000
+#define SERVER_START_BASE_TAG 2000
+#define SERVER_RECV_BASE_TAG 3000
+#define SERVER_END_BASE_TAG 4000
+
+ grpc_arg arg;
+ arg.key = GRPC_ARG_RESOURCE_QUOTA;
+ arg.type = GRPC_ARG_POINTER;
+ arg.value.pointer.p = resource_quota;
+ arg.value.pointer.vtable = grpc_resource_quota_arg_vtable();
+ grpc_channel_args args = {1, &arg};
+
+ grpc_end2end_test_fixture f =
+ begin_test(config, "resource_quota_server", NULL, &args);
+
+ /* Create large request and response bodies. These are big enough to require
+ * multiple round trips to deliver to the peer, and their exact contents of
+ * will be verified on completion. */
+ gpr_slice request_payload_slice = generate_random_slice();
+
+ grpc_call *client_calls[NUM_CALLS];
+ grpc_call *server_calls[NUM_CALLS];
+ grpc_metadata_array initial_metadata_recv[NUM_CALLS];
+ grpc_metadata_array trailing_metadata_recv[NUM_CALLS];
+ grpc_metadata_array request_metadata_recv[NUM_CALLS];
+ grpc_call_details call_details[NUM_CALLS];
+ grpc_status_code status[NUM_CALLS];
+ char *details[NUM_CALLS];
+ size_t details_capacity[NUM_CALLS];
+ grpc_byte_buffer *request_payload_recv[NUM_CALLS];
+ int was_cancelled[NUM_CALLS];
+ grpc_call_error error;
+ int pending_client_calls = 0;
+ int pending_server_start_calls = 0;
+ int pending_server_recv_calls = 0;
+ int pending_server_end_calls = 0;
+ int cancelled_calls_on_client = 0;
+ int cancelled_calls_on_server = 0;
+
+ grpc_byte_buffer *request_payload =
+ grpc_raw_byte_buffer_create(&request_payload_slice, 1);
+
+ grpc_op ops[6];
+ grpc_op *op;
+
+ for (int i = 0; i < NUM_CALLS; i++) {
+ grpc_metadata_array_init(&initial_metadata_recv[i]);
+ grpc_metadata_array_init(&trailing_metadata_recv[i]);
+ grpc_metadata_array_init(&request_metadata_recv[i]);
+ grpc_call_details_init(&call_details[i]);
+ details[i] = NULL;
+ details_capacity[i] = 0;
+ request_payload_recv[i] = NULL;
+ was_cancelled[i] = 0;
+ }
+
+ for (int i = 0; i < NUM_CALLS; i++) {
+ error = grpc_server_request_call(
+ f.server, &server_calls[i], &call_details[i], &request_metadata_recv[i],
+ f.cq, f.cq, tag(SERVER_START_BASE_TAG + i));
+ GPR_ASSERT(GRPC_CALL_OK == error);
+
+ pending_server_start_calls++;
+ }
+
+ for (int i = 0; i < NUM_CALLS; i++) {
+ client_calls[i] = grpc_channel_create_call(
+ f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, "/foo",
+ "foo.test.google.fr", n_seconds_time(60), NULL);
+
+ memset(ops, 0, sizeof(ops));
+ op = ops;
+ op->op = GRPC_OP_SEND_INITIAL_METADATA;
+ op->data.send_initial_metadata.count = 0;
+ op->flags = 0;
+ op->reserved = NULL;
+ op++;
+ op->op = GRPC_OP_SEND_MESSAGE;
+ op->data.send_message = request_payload;
+ op->flags = 0;
+ op->reserved = NULL;
+ op++;
+ op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
+ op->flags = 0;
+ op->reserved = NULL;
+ op++;
+ op->op = GRPC_OP_RECV_INITIAL_METADATA;
+ op->data.recv_initial_metadata = &initial_metadata_recv[i];
+ op->flags = 0;
+ op->reserved = NULL;
+ op++;
+ op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+ op->data.recv_status_on_client.trailing_metadata =
+ &trailing_metadata_recv[i];
+ op->data.recv_status_on_client.status = &status[i];
+ op->data.recv_status_on_client.status_details = &details[i];
+ op->data.recv_status_on_client.status_details_capacity =
+ &details_capacity[i];
+ op->flags = 0;
+ op->reserved = NULL;
+ op++;
+ error = grpc_call_start_batch(client_calls[i], ops, (size_t)(op - ops),
+ tag(CLIENT_BASE_TAG + i), NULL);
+ GPR_ASSERT(GRPC_CALL_OK == error);
+
+ pending_client_calls++;
+ }
+
+ while (pending_client_calls + pending_server_recv_calls +
+ pending_server_end_calls >
+ 0) {
+ grpc_event ev = grpc_completion_queue_next(f.cq, n_seconds_time(10), NULL);
+ GPR_ASSERT(ev.type == GRPC_OP_COMPLETE);
+
+ int ev_tag = (int)(intptr_t)ev.tag;
+ if (ev_tag < CLIENT_BASE_TAG) {
+ abort(); /* illegal tag */
+ } else if (ev_tag < SERVER_START_BASE_TAG) {
+ /* client call finished */
+ int call_id = ev_tag - CLIENT_BASE_TAG;
+ GPR_ASSERT(call_id >= 0);
+ GPR_ASSERT(call_id < NUM_CALLS);
+ switch (status[call_id]) {
+ case GRPC_STATUS_RESOURCE_EXHAUSTED:
+ cancelled_calls_on_client++;
+ break;
+ case GRPC_STATUS_OK:
+ break;
+ default:
+ gpr_log(GPR_ERROR, "Unexpected status code: %d", status[call_id]);
+ abort();
+ }
+ GPR_ASSERT(pending_client_calls > 0);
+
+ grpc_metadata_array_destroy(&initial_metadata_recv[call_id]);
+ grpc_metadata_array_destroy(&trailing_metadata_recv[call_id]);
+ grpc_call_destroy(client_calls[call_id]);
+ gpr_free(details[call_id]);
+
+ pending_client_calls--;
+ } else if (ev_tag < SERVER_RECV_BASE_TAG) {
+ /* new incoming call to the server */
+ int call_id = ev_tag - SERVER_START_BASE_TAG;
+ GPR_ASSERT(call_id >= 0);
+ GPR_ASSERT(call_id < NUM_CALLS);
+
+ memset(ops, 0, sizeof(ops));
+ op = ops;
+ op->op = GRPC_OP_SEND_INITIAL_METADATA;
+ op->data.send_initial_metadata.count = 0;
+ op->flags = 0;
+ op->reserved = NULL;
+ op++;
+ op->op = GRPC_OP_RECV_MESSAGE;
+ op->data.recv_message = &request_payload_recv[call_id];
+ op->flags = 0;
+ op->reserved = NULL;
+ op++;
+ error =
+ grpc_call_start_batch(server_calls[call_id], ops, (size_t)(op - ops),
+ tag(SERVER_RECV_BASE_TAG + call_id), NULL);
+ GPR_ASSERT(GRPC_CALL_OK == error);
+
+ GPR_ASSERT(pending_server_start_calls > 0);
+ pending_server_start_calls--;
+ pending_server_recv_calls++;
+
+ grpc_call_details_destroy(&call_details[call_id]);
+ grpc_metadata_array_destroy(&request_metadata_recv[call_id]);
+ } else if (ev_tag < SERVER_END_BASE_TAG) {
+ /* finished read on the server */
+ int call_id = ev_tag - SERVER_RECV_BASE_TAG;
+ GPR_ASSERT(call_id >= 0);
+ GPR_ASSERT(call_id < NUM_CALLS);
+
+ if (ev.success) {
+ if (request_payload_recv[call_id] != NULL) {
+ grpc_byte_buffer_destroy(request_payload_recv[call_id]);
+ request_payload_recv[call_id] = NULL;
+ }
+ } else {
+ GPR_ASSERT(request_payload_recv[call_id] == NULL);
+ }
+
+ memset(ops, 0, sizeof(ops));
+ op = ops;
+ op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
+ op->data.recv_close_on_server.cancelled = &was_cancelled[call_id];
+ op->flags = 0;
+ op->reserved = NULL;
+ op++;
+ op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+ op->data.send_status_from_server.trailing_metadata_count = 0;
+ op->data.send_status_from_server.status = GRPC_STATUS_OK;
+ op->data.send_status_from_server.status_details = "xyz";
+ op->flags = 0;
+ op->reserved = NULL;
+ op++;
+ error =
+ grpc_call_start_batch(server_calls[call_id], ops, (size_t)(op - ops),
+ tag(SERVER_END_BASE_TAG + call_id), NULL);
+ GPR_ASSERT(GRPC_CALL_OK == error);
+
+ GPR_ASSERT(pending_server_recv_calls > 0);
+ pending_server_recv_calls--;
+ pending_server_end_calls++;
+ } else {
+ int call_id = ev_tag - SERVER_END_BASE_TAG;
+ GPR_ASSERT(call_id >= 0);
+ GPR_ASSERT(call_id < NUM_CALLS);
+
+ if (was_cancelled[call_id]) {
+ cancelled_calls_on_server++;
+ }
+ GPR_ASSERT(pending_server_end_calls > 0);
+ pending_server_end_calls--;
+
+ grpc_call_destroy(server_calls[call_id]);
+ }
+ }
+
+ gpr_log(
+ GPR_INFO,
+ "Done. %d total calls: %d cancelled at server, %d cancelled at client.",
+ NUM_CALLS, cancelled_calls_on_server, cancelled_calls_on_client);
+
+ /* The call may be cancelled after the server has sent its status but before
+ * the client has received it. This means that we should see strictly more
+ * failures on the client than on the server. */
+ GPR_ASSERT(cancelled_calls_on_client >= cancelled_calls_on_server);
+ /* However, we shouldn't see radically more... 0.9 is a guessed bound on what
+ * we'd want that ratio to be... to at least trigger some investigation should
+ * that ratio become much higher. */
+ GPR_ASSERT(cancelled_calls_on_server >= 0.9 * cancelled_calls_on_client);
+
+ grpc_byte_buffer_destroy(request_payload);
+ gpr_slice_unref(request_payload_slice);
+ grpc_resource_quota_unref(resource_quota);
+
+ end_test(&f);
+ config.tear_down_data(&f);
+}
+
+void resource_quota_server_pre_init(void) {}
diff --git a/test/core/http/httpcli_test.c b/test/core/http/httpcli_test.c
index 38b32a3867..3e312c1dde 100644
--- a/test/core/http/httpcli_test.c
+++ b/test/core/http/httpcli_test.c
@@ -89,8 +89,11 @@ static void test_get(int port) {
grpc_http_response response;
memset(&response, 0, sizeof(response));
- grpc_httpcli_get(&exec_ctx, &g_context, &g_pops, &req, n_seconds_time(15),
+ grpc_resource_quota *resource_quota = grpc_resource_quota_create("test_get");
+ grpc_httpcli_get(&exec_ctx, &g_context, &g_pops, resource_quota, &req,
+ n_seconds_time(15),
grpc_closure_create(on_finish, &response), &response);
+ grpc_resource_quota_internal_unref(&exec_ctx, resource_quota);
gpr_mu_lock(g_mu);
while (!g_done) {
grpc_pollset_worker *worker = NULL;
@@ -126,9 +129,11 @@ static void test_post(int port) {
grpc_http_response response;
memset(&response, 0, sizeof(response));
- grpc_httpcli_post(&exec_ctx, &g_context, &g_pops, &req, "hello", 5,
- n_seconds_time(15),
+ grpc_resource_quota *resource_quota = grpc_resource_quota_create("test_post");
+ grpc_httpcli_post(&exec_ctx, &g_context, &g_pops, resource_quota, &req,
+ "hello", 5, n_seconds_time(15),
grpc_closure_create(on_finish, &response), &response);
+ grpc_resource_quota_internal_unref(&exec_ctx, resource_quota);
gpr_mu_lock(g_mu);
while (!g_done) {
grpc_pollset_worker *worker = NULL;
diff --git a/test/core/http/httpscli_test.c b/test/core/http/httpscli_test.c
index 359e557689..d06035149e 100644
--- a/test/core/http/httpscli_test.c
+++ b/test/core/http/httpscli_test.c
@@ -90,8 +90,11 @@ static void test_get(int port) {
grpc_http_response response;
memset(&response, 0, sizeof(response));
- grpc_httpcli_get(&exec_ctx, &g_context, &g_pops, &req, n_seconds_time(15),
+ grpc_resource_quota *resource_quota = grpc_resource_quota_create("test_get");
+ grpc_httpcli_get(&exec_ctx, &g_context, &g_pops, resource_quota, &req,
+ n_seconds_time(15),
grpc_closure_create(on_finish, &response), &response);
+ grpc_resource_quota_internal_unref(&exec_ctx, resource_quota);
gpr_mu_lock(g_mu);
while (!g_done) {
grpc_pollset_worker *worker = NULL;
@@ -128,9 +131,11 @@ static void test_post(int port) {
grpc_http_response response;
memset(&response, 0, sizeof(response));
- grpc_httpcli_post(&exec_ctx, &g_context, &g_pops, &req, "hello", 5,
- n_seconds_time(15),
+ grpc_resource_quota *resource_quota = grpc_resource_quota_create("test_post");
+ grpc_httpcli_post(&exec_ctx, &g_context, &g_pops, resource_quota, &req,
+ "hello", 5, n_seconds_time(15),
grpc_closure_create(on_finish, &response), &response);
+ grpc_resource_quota_internal_unref(&exec_ctx, resource_quota);
gpr_mu_lock(g_mu);
while (!g_done) {
grpc_pollset_worker *worker = NULL;
diff --git a/test/core/internal_api_canaries/iomgr.c b/test/core/internal_api_canaries/iomgr.c
index 27d630623e..f1efa87a69 100644
--- a/test/core/internal_api_canaries/iomgr.c
+++ b/test/core/internal_api_canaries/iomgr.c
@@ -84,6 +84,7 @@ static void test_code(void) {
grpc_endpoint_add_to_pollset_set,
grpc_endpoint_shutdown,
grpc_endpoint_destroy,
+ grpc_endpoint_get_resource_user,
grpc_endpoint_get_peer};
endpoint.vtable = &vtable;
diff --git a/test/core/iomgr/endpoint_pair_test.c b/test/core/iomgr/endpoint_pair_test.c
index 99b86b6213..2a257a7cea 100644
--- a/test/core/iomgr/endpoint_pair_test.c
+++ b/test/core/iomgr/endpoint_pair_test.c
@@ -49,7 +49,11 @@ static grpc_endpoint_test_fixture create_fixture_endpoint_pair(
size_t slice_size) {
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
grpc_endpoint_test_fixture f;
- grpc_endpoint_pair p = grpc_iomgr_create_endpoint_pair("test", slice_size);
+ grpc_resource_quota *resource_quota =
+ grpc_resource_quota_create("endpoint_pair_test");
+ grpc_endpoint_pair p =
+ grpc_iomgr_create_endpoint_pair("test", resource_quota, slice_size);
+ grpc_resource_quota_unref(resource_quota);
f.client_ep = p.client;
f.server_ep = p.server;
diff --git a/test/core/iomgr/fd_conservation_posix_test.c b/test/core/iomgr/fd_conservation_posix_test.c
index bbb3f46497..652b37eb6f 100644
--- a/test/core/iomgr/fd_conservation_posix_test.c
+++ b/test/core/iomgr/fd_conservation_posix_test.c
@@ -52,15 +52,19 @@ int main(int argc, char **argv) {
of descriptors */
rlim.rlim_cur = rlim.rlim_max = 10;
GPR_ASSERT(0 == setrlimit(RLIMIT_NOFILE, &rlim));
+ grpc_resource_quota *resource_quota =
+ grpc_resource_quota_create("fd_conservation_posix_test");
for (i = 0; i < 100; i++) {
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
- p = grpc_iomgr_create_endpoint_pair("test", 1);
+ p = grpc_iomgr_create_endpoint_pair("test", resource_quota, 1);
grpc_endpoint_destroy(&exec_ctx, p.client);
grpc_endpoint_destroy(&exec_ctx, p.server);
grpc_exec_ctx_finish(&exec_ctx);
}
+ grpc_resource_quota_unref(resource_quota);
+
grpc_iomgr_shutdown();
return 0;
}
diff --git a/test/core/iomgr/resource_quota_test.c b/test/core/iomgr/resource_quota_test.c
new file mode 100644
index 0000000000..34dee1aee1
--- /dev/null
+++ b/test/core/iomgr/resource_quota_test.c
@@ -0,0 +1,749 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/iomgr/resource_quota.h"
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include "test/core/util/test_config.h"
+
+static void inc_int_cb(grpc_exec_ctx *exec_ctx, void *a, grpc_error *error) {
+ ++*(int *)a;
+}
+
+static void set_bool_cb(grpc_exec_ctx *exec_ctx, void *a, grpc_error *error) {
+ *(bool *)a = true;
+}
+grpc_closure *set_bool(bool *p) { return grpc_closure_create(set_bool_cb, p); }
+
+typedef struct {
+ size_t size;
+ grpc_resource_user *resource_user;
+ grpc_closure *then;
+} reclaimer_args;
+static void reclaimer_cb(grpc_exec_ctx *exec_ctx, void *args,
+ grpc_error *error) {
+ GPR_ASSERT(error == GRPC_ERROR_NONE);
+ reclaimer_args *a = args;
+ grpc_resource_user_free(exec_ctx, a->resource_user, a->size);
+ grpc_resource_user_finish_reclamation(exec_ctx, a->resource_user);
+ grpc_closure_run(exec_ctx, a->then, GRPC_ERROR_NONE);
+ gpr_free(a);
+}
+grpc_closure *make_reclaimer(grpc_resource_user *resource_user, size_t size,
+ grpc_closure *then) {
+ reclaimer_args *a = gpr_malloc(sizeof(*a));
+ a->size = size;
+ a->resource_user = resource_user;
+ a->then = then;
+ return grpc_closure_create(reclaimer_cb, a);
+}
+
+static void unused_reclaimer_cb(grpc_exec_ctx *exec_ctx, void *arg,
+ grpc_error *error) {
+ GPR_ASSERT(error == GRPC_ERROR_CANCELLED);
+ grpc_closure_run(exec_ctx, arg, GRPC_ERROR_NONE);
+}
+grpc_closure *make_unused_reclaimer(grpc_closure *then) {
+ return grpc_closure_create(unused_reclaimer_cb, then);
+}
+
+static void destroy_user(grpc_resource_user *usr) {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ bool done = false;
+ grpc_resource_user_shutdown(&exec_ctx, usr, set_bool(&done));
+ grpc_exec_ctx_flush(&exec_ctx);
+ GPR_ASSERT(done);
+ grpc_resource_user_destroy(&exec_ctx, usr);
+ grpc_exec_ctx_finish(&exec_ctx);
+}
+
+static void test_no_op(void) {
+ gpr_log(GPR_INFO, "** test_no_op **");
+ grpc_resource_quota_unref(grpc_resource_quota_create("test_no_op"));
+}
+
+static void test_resize_then_destroy(void) {
+ gpr_log(GPR_INFO, "** test_resize_then_destroy **");
+ grpc_resource_quota *q =
+ grpc_resource_quota_create("test_resize_then_destroy");
+ grpc_resource_quota_resize(q, 1024 * 1024);
+ grpc_resource_quota_unref(q);
+}
+
+static void test_resource_user_no_op(void) {
+ gpr_log(GPR_INFO, "** test_resource_user_no_op **");
+ grpc_resource_quota *q =
+ grpc_resource_quota_create("test_resource_user_no_op");
+ grpc_resource_user usr;
+ grpc_resource_user_init(&usr, q, "usr");
+ grpc_resource_quota_unref(q);
+ destroy_user(&usr);
+}
+
+static void test_instant_alloc_then_free(void) {
+ gpr_log(GPR_INFO, "** test_instant_alloc_then_free **");
+ grpc_resource_quota *q =
+ grpc_resource_quota_create("test_instant_alloc_then_free");
+ grpc_resource_quota_resize(q, 1024 * 1024);
+ grpc_resource_user usr;
+ grpc_resource_user_init(&usr, q, "usr");
+ {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_alloc(&exec_ctx, &usr, 1024, NULL);
+ grpc_exec_ctx_finish(&exec_ctx);
+ }
+ {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_free(&exec_ctx, &usr, 1024);
+ grpc_exec_ctx_finish(&exec_ctx);
+ }
+ grpc_resource_quota_unref(q);
+ destroy_user(&usr);
+}
+
+static void test_instant_alloc_free_pair(void) {
+ gpr_log(GPR_INFO, "** test_instant_alloc_free_pair **");
+ grpc_resource_quota *q =
+ grpc_resource_quota_create("test_instant_alloc_free_pair");
+ grpc_resource_quota_resize(q, 1024 * 1024);
+ grpc_resource_user usr;
+ grpc_resource_user_init(&usr, q, "usr");
+ {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_alloc(&exec_ctx, &usr, 1024, NULL);
+ grpc_resource_user_free(&exec_ctx, &usr, 1024);
+ grpc_exec_ctx_finish(&exec_ctx);
+ }
+ grpc_resource_quota_unref(q);
+ destroy_user(&usr);
+}
+
+static void test_simple_async_alloc(void) {
+ gpr_log(GPR_INFO, "** test_simple_async_alloc **");
+ grpc_resource_quota *q =
+ grpc_resource_quota_create("test_simple_async_alloc");
+ grpc_resource_quota_resize(q, 1024 * 1024);
+ grpc_resource_user usr;
+ grpc_resource_user_init(&usr, q, "usr");
+ {
+ bool done = false;
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_alloc(&exec_ctx, &usr, 1024, set_bool(&done));
+ grpc_exec_ctx_finish(&exec_ctx);
+ GPR_ASSERT(done);
+ }
+ {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_free(&exec_ctx, &usr, 1024);
+ grpc_exec_ctx_finish(&exec_ctx);
+ }
+ grpc_resource_quota_unref(q);
+ destroy_user(&usr);
+}
+
+static void test_async_alloc_blocked_by_size(void) {
+ gpr_log(GPR_INFO, "** test_async_alloc_blocked_by_size **");
+ grpc_resource_quota *q =
+ grpc_resource_quota_create("test_async_alloc_blocked_by_size");
+ grpc_resource_quota_resize(q, 1);
+ grpc_resource_user usr;
+ grpc_resource_user_init(&usr, q, "usr");
+ bool done = false;
+ {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_alloc(&exec_ctx, &usr, 1024, set_bool(&done));
+ grpc_exec_ctx_finish(&exec_ctx);
+ GPR_ASSERT(!done);
+ }
+ grpc_resource_quota_resize(q, 1024);
+ GPR_ASSERT(done);
+ {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_free(&exec_ctx, &usr, 1024);
+ grpc_exec_ctx_finish(&exec_ctx);
+ }
+ grpc_resource_quota_unref(q);
+ destroy_user(&usr);
+}
+
+static void test_scavenge(void) {
+ gpr_log(GPR_INFO, "** test_scavenge **");
+ grpc_resource_quota *q = grpc_resource_quota_create("test_scavenge");
+ grpc_resource_quota_resize(q, 1024);
+ grpc_resource_user usr1;
+ grpc_resource_user usr2;
+ grpc_resource_user_init(&usr1, q, "usr1");
+ grpc_resource_user_init(&usr2, q, "usr2");
+ {
+ bool done = false;
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_alloc(&exec_ctx, &usr1, 1024, set_bool(&done));
+ grpc_exec_ctx_finish(&exec_ctx);
+ GPR_ASSERT(done);
+ }
+ {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_free(&exec_ctx, &usr1, 1024);
+ grpc_exec_ctx_finish(&exec_ctx);
+ }
+ {
+ bool done = false;
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_alloc(&exec_ctx, &usr2, 1024, set_bool(&done));
+ grpc_exec_ctx_finish(&exec_ctx);
+ GPR_ASSERT(done);
+ }
+ {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_free(&exec_ctx, &usr2, 1024);
+ grpc_exec_ctx_finish(&exec_ctx);
+ }
+ grpc_resource_quota_unref(q);
+ destroy_user(&usr1);
+ destroy_user(&usr2);
+}
+
+static void test_scavenge_blocked(void) {
+ gpr_log(GPR_INFO, "** test_scavenge_blocked **");
+ grpc_resource_quota *q = grpc_resource_quota_create("test_scavenge_blocked");
+ grpc_resource_quota_resize(q, 1024);
+ grpc_resource_user usr1;
+ grpc_resource_user usr2;
+ grpc_resource_user_init(&usr1, q, "usr1");
+ grpc_resource_user_init(&usr2, q, "usr2");
+ bool done;
+ {
+ done = false;
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_alloc(&exec_ctx, &usr1, 1024, set_bool(&done));
+ grpc_exec_ctx_finish(&exec_ctx);
+ GPR_ASSERT(done);
+ }
+ {
+ done = false;
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_alloc(&exec_ctx, &usr2, 1024, set_bool(&done));
+ grpc_exec_ctx_finish(&exec_ctx);
+ GPR_ASSERT(!done);
+ }
+ {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_free(&exec_ctx, &usr1, 1024);
+ grpc_exec_ctx_finish(&exec_ctx);
+ GPR_ASSERT(done);
+ }
+ {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_free(&exec_ctx, &usr2, 1024);
+ grpc_exec_ctx_finish(&exec_ctx);
+ }
+ grpc_resource_quota_unref(q);
+ destroy_user(&usr1);
+ destroy_user(&usr2);
+}
+
+static void test_blocked_until_scheduled_reclaim(void) {
+ gpr_log(GPR_INFO, "** test_blocked_until_scheduled_reclaim **");
+ grpc_resource_quota *q =
+ grpc_resource_quota_create("test_blocked_until_scheduled_reclaim");
+ grpc_resource_quota_resize(q, 1024);
+ grpc_resource_user usr;
+ grpc_resource_user_init(&usr, q, "usr");
+ {
+ bool done = false;
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_alloc(&exec_ctx, &usr, 1024, set_bool(&done));
+ grpc_exec_ctx_finish(&exec_ctx);
+ GPR_ASSERT(done);
+ }
+ bool reclaim_done = false;
+ {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_post_reclaimer(
+ &exec_ctx, &usr, false,
+ make_reclaimer(&usr, 1024, set_bool(&reclaim_done)));
+ grpc_exec_ctx_finish(&exec_ctx);
+ }
+ {
+ bool done = false;
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_alloc(&exec_ctx, &usr, 1024, set_bool(&done));
+ grpc_exec_ctx_finish(&exec_ctx);
+ GPR_ASSERT(reclaim_done);
+ GPR_ASSERT(done);
+ }
+ {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_free(&exec_ctx, &usr, 1024);
+ grpc_exec_ctx_finish(&exec_ctx);
+ }
+ grpc_resource_quota_unref(q);
+ destroy_user(&usr);
+}
+
+static void test_blocked_until_scheduled_reclaim_and_scavenge(void) {
+ gpr_log(GPR_INFO, "** test_blocked_until_scheduled_reclaim_and_scavenge **");
+ grpc_resource_quota *q = grpc_resource_quota_create(
+ "test_blocked_until_scheduled_reclaim_and_scavenge");
+ grpc_resource_quota_resize(q, 1024);
+ grpc_resource_user usr1;
+ grpc_resource_user usr2;
+ grpc_resource_user_init(&usr1, q, "usr1");
+ grpc_resource_user_init(&usr2, q, "usr2");
+ {
+ bool done = false;
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_alloc(&exec_ctx, &usr1, 1024, set_bool(&done));
+ grpc_exec_ctx_finish(&exec_ctx);
+ GPR_ASSERT(done);
+ }
+ bool reclaim_done = false;
+ {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_post_reclaimer(
+ &exec_ctx, &usr1, false,
+ make_reclaimer(&usr1, 1024, set_bool(&reclaim_done)));
+ grpc_exec_ctx_finish(&exec_ctx);
+ }
+ {
+ bool done = false;
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_alloc(&exec_ctx, &usr2, 1024, set_bool(&done));
+ grpc_exec_ctx_finish(&exec_ctx);
+ GPR_ASSERT(reclaim_done);
+ GPR_ASSERT(done);
+ }
+ {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_free(&exec_ctx, &usr2, 1024);
+ grpc_exec_ctx_finish(&exec_ctx);
+ }
+ grpc_resource_quota_unref(q);
+ destroy_user(&usr1);
+ destroy_user(&usr2);
+}
+
+static void test_blocked_until_scheduled_destructive_reclaim(void) {
+ gpr_log(GPR_INFO, "** test_blocked_until_scheduled_destructive_reclaim **");
+ grpc_resource_quota *q = grpc_resource_quota_create(
+ "test_blocked_until_scheduled_destructive_reclaim");
+ grpc_resource_quota_resize(q, 1024);
+ grpc_resource_user usr;
+ grpc_resource_user_init(&usr, q, "usr");
+ {
+ bool done = false;
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_alloc(&exec_ctx, &usr, 1024, set_bool(&done));
+ grpc_exec_ctx_finish(&exec_ctx);
+ GPR_ASSERT(done);
+ }
+ bool reclaim_done = false;
+ {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_post_reclaimer(
+ &exec_ctx, &usr, true,
+ make_reclaimer(&usr, 1024, set_bool(&reclaim_done)));
+ grpc_exec_ctx_finish(&exec_ctx);
+ }
+ {
+ bool done = false;
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_alloc(&exec_ctx, &usr, 1024, set_bool(&done));
+ grpc_exec_ctx_finish(&exec_ctx);
+ GPR_ASSERT(reclaim_done);
+ GPR_ASSERT(done);
+ }
+ {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_free(&exec_ctx, &usr, 1024);
+ grpc_exec_ctx_finish(&exec_ctx);
+ }
+ grpc_resource_quota_unref(q);
+ destroy_user(&usr);
+}
+
+static void test_unused_reclaim_is_cancelled(void) {
+ gpr_log(GPR_INFO, "** test_unused_reclaim_is_cancelled **");
+ grpc_resource_quota *q =
+ grpc_resource_quota_create("test_unused_reclaim_is_cancelled");
+ grpc_resource_quota_resize(q, 1024);
+ grpc_resource_user usr;
+ grpc_resource_user_init(&usr, q, "usr");
+ bool benign_done = false;
+ bool destructive_done = false;
+ {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_post_reclaimer(
+ &exec_ctx, &usr, false, make_unused_reclaimer(set_bool(&benign_done)));
+ grpc_resource_user_post_reclaimer(
+ &exec_ctx, &usr, true,
+ make_unused_reclaimer(set_bool(&destructive_done)));
+ grpc_exec_ctx_finish(&exec_ctx);
+ GPR_ASSERT(!benign_done);
+ GPR_ASSERT(!destructive_done);
+ }
+ grpc_resource_quota_unref(q);
+ destroy_user(&usr);
+ GPR_ASSERT(benign_done);
+ GPR_ASSERT(destructive_done);
+}
+
+static void test_benign_reclaim_is_preferred(void) {
+ gpr_log(GPR_INFO, "** test_benign_reclaim_is_preferred **");
+ grpc_resource_quota *q =
+ grpc_resource_quota_create("test_benign_reclaim_is_preferred");
+ grpc_resource_quota_resize(q, 1024);
+ grpc_resource_user usr;
+ grpc_resource_user_init(&usr, q, "usr");
+ bool benign_done = false;
+ bool destructive_done = false;
+ {
+ bool done = false;
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_alloc(&exec_ctx, &usr, 1024, set_bool(&done));
+ grpc_exec_ctx_finish(&exec_ctx);
+ GPR_ASSERT(done);
+ }
+ {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_post_reclaimer(
+ &exec_ctx, &usr, false,
+ make_reclaimer(&usr, 1024, set_bool(&benign_done)));
+ grpc_resource_user_post_reclaimer(
+ &exec_ctx, &usr, true,
+ make_unused_reclaimer(set_bool(&destructive_done)));
+ grpc_exec_ctx_finish(&exec_ctx);
+ GPR_ASSERT(!benign_done);
+ GPR_ASSERT(!destructive_done);
+ }
+ {
+ bool done = false;
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_alloc(&exec_ctx, &usr, 1024, set_bool(&done));
+ grpc_exec_ctx_finish(&exec_ctx);
+ GPR_ASSERT(benign_done);
+ GPR_ASSERT(!destructive_done);
+ GPR_ASSERT(done);
+ }
+ {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_free(&exec_ctx, &usr, 1024);
+ grpc_exec_ctx_finish(&exec_ctx);
+ }
+ grpc_resource_quota_unref(q);
+ destroy_user(&usr);
+ GPR_ASSERT(benign_done);
+ GPR_ASSERT(destructive_done);
+}
+
+static void test_multiple_reclaims_can_be_triggered(void) {
+ gpr_log(GPR_INFO, "** test_multiple_reclaims_can_be_triggered **");
+ grpc_resource_quota *q =
+ grpc_resource_quota_create("test_multiple_reclaims_can_be_triggered");
+ grpc_resource_quota_resize(q, 1024);
+ grpc_resource_user usr;
+ grpc_resource_user_init(&usr, q, "usr");
+ bool benign_done = false;
+ bool destructive_done = false;
+ {
+ bool done = false;
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_alloc(&exec_ctx, &usr, 1024, set_bool(&done));
+ grpc_exec_ctx_finish(&exec_ctx);
+ GPR_ASSERT(done);
+ }
+ {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_post_reclaimer(
+ &exec_ctx, &usr, false,
+ make_reclaimer(&usr, 512, set_bool(&benign_done)));
+ grpc_resource_user_post_reclaimer(
+ &exec_ctx, &usr, true,
+ make_reclaimer(&usr, 512, set_bool(&destructive_done)));
+ grpc_exec_ctx_finish(&exec_ctx);
+ GPR_ASSERT(!benign_done);
+ GPR_ASSERT(!destructive_done);
+ }
+ {
+ bool done = false;
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_alloc(&exec_ctx, &usr, 1024, set_bool(&done));
+ grpc_exec_ctx_finish(&exec_ctx);
+ GPR_ASSERT(benign_done);
+ GPR_ASSERT(destructive_done);
+ GPR_ASSERT(done);
+ }
+ {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_free(&exec_ctx, &usr, 1024);
+ grpc_exec_ctx_finish(&exec_ctx);
+ }
+ grpc_resource_quota_unref(q);
+ destroy_user(&usr);
+ GPR_ASSERT(benign_done);
+ GPR_ASSERT(destructive_done);
+}
+
+static void test_resource_user_stays_allocated_until_memory_released(void) {
+ gpr_log(GPR_INFO,
+ "** test_resource_user_stays_allocated_until_memory_released **");
+ grpc_resource_quota *q = grpc_resource_quota_create(
+ "test_resource_user_stays_allocated_until_memory_released");
+ grpc_resource_quota_resize(q, 1024 * 1024);
+ grpc_resource_user usr;
+ grpc_resource_user_init(&usr, q, "usr");
+ bool done = false;
+ {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_alloc(&exec_ctx, &usr, 1024, NULL);
+ grpc_exec_ctx_finish(&exec_ctx);
+ }
+ {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_quota_unref(q);
+ grpc_resource_user_shutdown(&exec_ctx, &usr, set_bool(&done));
+ grpc_exec_ctx_finish(&exec_ctx);
+ GPR_ASSERT(!done);
+ }
+ {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_free(&exec_ctx, &usr, 1024);
+ grpc_exec_ctx_finish(&exec_ctx);
+ GPR_ASSERT(done);
+ }
+ {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_destroy(&exec_ctx, &usr);
+ grpc_exec_ctx_finish(&exec_ctx);
+ }
+}
+
+static void
+test_resource_user_stays_allocated_and_reclaimers_unrun_until_memory_released(
+ void) {
+ gpr_log(GPR_INFO,
+ "** "
+ "test_resource_user_stays_allocated_and_reclaimers_unrun_until_"
+ "memory_released **");
+ grpc_resource_quota *q = grpc_resource_quota_create(
+ "test_resource_user_stays_allocated_and_reclaimers_unrun_until_memory_"
+ "released");
+ grpc_resource_quota_resize(q, 1024);
+ for (int i = 0; i < 10; i++) {
+ grpc_resource_user usr;
+ grpc_resource_user_init(&usr, q, "usr");
+ bool done = false;
+ bool reclaimer_cancelled = false;
+ {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_post_reclaimer(
+ &exec_ctx, &usr, false,
+ make_unused_reclaimer(set_bool(&reclaimer_cancelled)));
+ grpc_exec_ctx_finish(&exec_ctx);
+ GPR_ASSERT(!reclaimer_cancelled);
+ }
+ {
+ bool allocated = false;
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_alloc(&exec_ctx, &usr, 1024, set_bool(&allocated));
+ grpc_exec_ctx_finish(&exec_ctx);
+ GPR_ASSERT(allocated);
+ GPR_ASSERT(!reclaimer_cancelled);
+ }
+ {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_shutdown(&exec_ctx, &usr, set_bool(&done));
+ grpc_exec_ctx_finish(&exec_ctx);
+ GPR_ASSERT(!done);
+ GPR_ASSERT(!reclaimer_cancelled);
+ }
+ {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_free(&exec_ctx, &usr, 1024);
+ grpc_exec_ctx_finish(&exec_ctx);
+ GPR_ASSERT(done);
+ GPR_ASSERT(reclaimer_cancelled);
+ }
+ {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_destroy(&exec_ctx, &usr);
+ grpc_exec_ctx_finish(&exec_ctx);
+ }
+ }
+ grpc_resource_quota_unref(q);
+}
+
+static void test_reclaimers_can_be_posted_repeatedly(void) {
+ gpr_log(GPR_INFO, "** test_reclaimers_can_be_posted_repeatedly **");
+ grpc_resource_quota *q =
+ grpc_resource_quota_create("test_reclaimers_can_be_posted_repeatedly");
+ grpc_resource_quota_resize(q, 1024);
+ grpc_resource_user usr;
+ grpc_resource_user_init(&usr, q, "usr");
+ {
+ bool allocated = false;
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_alloc(&exec_ctx, &usr, 1024, set_bool(&allocated));
+ grpc_exec_ctx_finish(&exec_ctx);
+ GPR_ASSERT(allocated);
+ }
+ for (int i = 0; i < 10; i++) {
+ bool reclaimer_done = false;
+ {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_post_reclaimer(
+ &exec_ctx, &usr, false,
+ make_reclaimer(&usr, 1024, set_bool(&reclaimer_done)));
+ grpc_exec_ctx_finish(&exec_ctx);
+ GPR_ASSERT(!reclaimer_done);
+ }
+ {
+ bool allocated = false;
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_alloc(&exec_ctx, &usr, 1024, set_bool(&allocated));
+ grpc_exec_ctx_finish(&exec_ctx);
+ GPR_ASSERT(allocated);
+ GPR_ASSERT(reclaimer_done);
+ }
+ }
+ {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_free(&exec_ctx, &usr, 1024);
+ grpc_exec_ctx_finish(&exec_ctx);
+ }
+ destroy_user(&usr);
+ grpc_resource_quota_unref(q);
+}
+
+static void test_one_slice(void) {
+ gpr_log(GPR_INFO, "** test_one_slice **");
+
+ grpc_resource_quota *q = grpc_resource_quota_create("test_one_slice");
+ grpc_resource_quota_resize(q, 1024);
+
+ grpc_resource_user usr;
+ grpc_resource_user_init(&usr, q, "usr");
+
+ grpc_resource_user_slice_allocator alloc;
+ int num_allocs = 0;
+ grpc_resource_user_slice_allocator_init(&alloc, &usr, inc_int_cb,
+ &num_allocs);
+
+ gpr_slice_buffer buffer;
+ gpr_slice_buffer_init(&buffer);
+
+ {
+ const int start_allocs = num_allocs;
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_alloc_slices(&exec_ctx, &alloc, 1024, 1, &buffer);
+ grpc_exec_ctx_finish(&exec_ctx);
+ GPR_ASSERT(num_allocs == start_allocs + 1);
+ }
+
+ gpr_slice_buffer_destroy(&buffer);
+ destroy_user(&usr);
+ grpc_resource_quota_unref(q);
+}
+
+static void test_one_slice_deleted_late(void) {
+ gpr_log(GPR_INFO, "** test_one_slice_deleted_late **");
+
+ grpc_resource_quota *q =
+ grpc_resource_quota_create("test_one_slice_deleted_late");
+ grpc_resource_quota_resize(q, 1024);
+
+ grpc_resource_user usr;
+ grpc_resource_user_init(&usr, q, "usr");
+
+ grpc_resource_user_slice_allocator alloc;
+ int num_allocs = 0;
+ grpc_resource_user_slice_allocator_init(&alloc, &usr, inc_int_cb,
+ &num_allocs);
+
+ gpr_slice_buffer buffer;
+ gpr_slice_buffer_init(&buffer);
+
+ {
+ const int start_allocs = num_allocs;
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_alloc_slices(&exec_ctx, &alloc, 1024, 1, &buffer);
+ grpc_exec_ctx_finish(&exec_ctx);
+ GPR_ASSERT(num_allocs == start_allocs + 1);
+ }
+
+ bool done = false;
+ {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_shutdown(&exec_ctx, &usr, set_bool(&done));
+ grpc_exec_ctx_finish(&exec_ctx);
+ GPR_ASSERT(!done);
+ }
+
+ grpc_resource_quota_unref(q);
+ gpr_slice_buffer_destroy(&buffer);
+ GPR_ASSERT(done);
+ {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_resource_user_destroy(&exec_ctx, &usr);
+ grpc_exec_ctx_finish(&exec_ctx);
+ }
+}
+
+int main(int argc, char **argv) {
+ grpc_test_init(argc, argv);
+ grpc_init();
+ test_no_op();
+ test_resize_then_destroy();
+ test_resource_user_no_op();
+ test_instant_alloc_then_free();
+ test_instant_alloc_free_pair();
+ test_simple_async_alloc();
+ test_async_alloc_blocked_by_size();
+ test_scavenge();
+ test_scavenge_blocked();
+ test_blocked_until_scheduled_reclaim();
+ test_blocked_until_scheduled_reclaim_and_scavenge();
+ test_blocked_until_scheduled_destructive_reclaim();
+ test_unused_reclaim_is_cancelled();
+ test_benign_reclaim_is_preferred();
+ test_multiple_reclaims_can_be_triggered();
+ test_resource_user_stays_allocated_until_memory_released();
+ test_resource_user_stays_allocated_and_reclaimers_unrun_until_memory_released();
+ test_reclaimers_can_be_posted_repeatedly();
+ test_one_slice();
+ test_one_slice_deleted_late();
+ grpc_shutdown();
+ return 0;
+}
diff --git a/test/core/iomgr/tcp_client_posix_test.c b/test/core/iomgr/tcp_client_posix_test.c
index 6c6962ed7a..5fab826fb7 100644
--- a/test/core/iomgr/tcp_client_posix_test.c
+++ b/test/core/iomgr/tcp_client_posix_test.c
@@ -114,7 +114,7 @@ void test_succeeds(void) {
GPR_ASSERT(getsockname(svr_fd, (struct sockaddr *)addr,
(socklen_t *)&resolved_addr.len) == 0);
grpc_closure_init(&done, must_succeed, NULL);
- grpc_tcp_client_connect(&exec_ctx, &done, &g_connecting, g_pollset_set,
+ grpc_tcp_client_connect(&exec_ctx, &done, &g_connecting, g_pollset_set, NULL,
&resolved_addr, gpr_inf_future(GPR_CLOCK_REALTIME));
/* await the connection */
@@ -164,7 +164,7 @@ void test_fails(void) {
/* connect to a broken address */
grpc_closure_init(&done, must_fail, NULL);
- grpc_tcp_client_connect(&exec_ctx, &done, &g_connecting, g_pollset_set,
+ grpc_tcp_client_connect(&exec_ctx, &done, &g_connecting, g_pollset_set, NULL,
&resolved_addr, gpr_inf_future(GPR_CLOCK_REALTIME));
gpr_mu_lock(g_mu);
diff --git a/test/core/iomgr/tcp_posix_test.c b/test/core/iomgr/tcp_posix_test.c
index d998958744..29f12a5afb 100644
--- a/test/core/iomgr/tcp_posix_test.c
+++ b/test/core/iomgr/tcp_posix_test.c
@@ -181,7 +181,10 @@ static void read_test(size_t num_bytes, size_t slice_size) {
create_sockets(sv);
- ep = grpc_tcp_create(grpc_fd_create(sv[1], "read_test"), slice_size, "test");
+ grpc_resource_quota *resource_quota = grpc_resource_quota_create("read_test");
+ ep = grpc_tcp_create(grpc_fd_create(sv[1], "read_test"), resource_quota,
+ slice_size, "test");
+ grpc_resource_quota_internal_unref(&exec_ctx, resource_quota);
grpc_endpoint_add_to_pollset(&exec_ctx, ep, g_pollset);
written_bytes = fill_socket_partial(sv[0], num_bytes);
@@ -228,8 +231,11 @@ static void large_read_test(size_t slice_size) {
create_sockets(sv);
- ep = grpc_tcp_create(grpc_fd_create(sv[1], "large_read_test"), slice_size,
- "test");
+ grpc_resource_quota *resource_quota =
+ grpc_resource_quota_create("large_read_test");
+ ep = grpc_tcp_create(grpc_fd_create(sv[1], "large_read_test"), resource_quota,
+ slice_size, "test");
+ grpc_resource_quota_internal_unref(&exec_ctx, resource_quota);
grpc_endpoint_add_to_pollset(&exec_ctx, ep, g_pollset);
written_bytes = fill_socket(sv[0]);
@@ -364,8 +370,11 @@ static void write_test(size_t num_bytes, size_t slice_size) {
create_sockets(sv);
- ep = grpc_tcp_create(grpc_fd_create(sv[1], "write_test"),
+ grpc_resource_quota *resource_quota =
+ grpc_resource_quota_create("write_test");
+ ep = grpc_tcp_create(grpc_fd_create(sv[1], "write_test"), resource_quota,
GRPC_TCP_DEFAULT_READ_SLICE_SIZE, "test");
+ grpc_resource_quota_internal_unref(&exec_ctx, resource_quota);
grpc_endpoint_add_to_pollset(&exec_ctx, ep, g_pollset);
state.ep = ep;
@@ -428,8 +437,12 @@ static void release_fd_test(size_t num_bytes, size_t slice_size) {
create_sockets(sv);
- ep = grpc_tcp_create(grpc_fd_create(sv[1], "read_test"), slice_size, "test");
+ grpc_resource_quota *resource_quota =
+ grpc_resource_quota_create("release_fd_test");
+ ep = grpc_tcp_create(grpc_fd_create(sv[1], "read_test"), resource_quota,
+ slice_size, "test");
GPR_ASSERT(grpc_tcp_fd(ep) == sv[1] && sv[1] >= 0);
+ grpc_resource_quota_internal_unref(&exec_ctx, resource_quota);
grpc_endpoint_add_to_pollset(&exec_ctx, ep, g_pollset);
written_bytes = fill_socket_partial(sv[0], num_bytes);
@@ -450,8 +463,10 @@ static void release_fd_test(size_t num_bytes, size_t slice_size) {
"pollset_work",
grpc_pollset_work(&exec_ctx, g_pollset, &worker,
gpr_now(GPR_CLOCK_MONOTONIC), deadline)));
+ gpr_log(GPR_DEBUG, "wakeup: read=%" PRIdPTR " target=%" PRIdPTR,
+ state.read_bytes, state.target_read_bytes);
gpr_mu_unlock(g_mu);
- grpc_exec_ctx_finish(&exec_ctx);
+ grpc_exec_ctx_flush(&exec_ctx);
gpr_mu_lock(g_mu);
}
GPR_ASSERT(state.read_bytes == state.target_read_bytes);
@@ -459,6 +474,7 @@ static void release_fd_test(size_t num_bytes, size_t slice_size) {
gpr_slice_buffer_destroy(&state.incoming);
grpc_tcp_destroy_and_release_fd(&exec_ctx, ep, &fd, &fd_released_cb);
+ grpc_exec_ctx_flush(&exec_ctx);
gpr_mu_lock(g_mu);
while (!fd_released_done) {
grpc_pollset_worker *worker = NULL;
@@ -466,6 +482,7 @@ static void release_fd_test(size_t num_bytes, size_t slice_size) {
"pollset_work",
grpc_pollset_work(&exec_ctx, g_pollset, &worker,
gpr_now(GPR_CLOCK_MONOTONIC), deadline)));
+ gpr_log(GPR_DEBUG, "wakeup: fd_released_done=%d", fd_released_done);
}
gpr_mu_unlock(g_mu);
GPR_ASSERT(fd_released_done == 1);
@@ -511,10 +528,13 @@ static grpc_endpoint_test_fixture create_fixture_tcp_socketpair(
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
create_sockets(sv);
+ grpc_resource_quota *resource_quota =
+ grpc_resource_quota_create("tcp_posix_test_socketpair");
f.client_ep = grpc_tcp_create(grpc_fd_create(sv[0], "fixture:client"),
- slice_size, "test");
+ resource_quota, slice_size, "test");
f.server_ep = grpc_tcp_create(grpc_fd_create(sv[1], "fixture:server"),
- slice_size, "test");
+ resource_quota, slice_size, "test");
+ grpc_resource_quota_internal_unref(&exec_ctx, resource_quota);
grpc_endpoint_add_to_pollset(&exec_ctx, f.client_ep, g_pollset);
grpc_endpoint_add_to_pollset(&exec_ctx, f.server_ep, g_pollset);
diff --git a/test/core/iomgr/tcp_server_posix_test.c b/test/core/iomgr/tcp_server_posix_test.c
index f839911a84..1b8a39c1be 100644
--- a/test/core/iomgr/tcp_server_posix_test.c
+++ b/test/core/iomgr/tcp_server_posix_test.c
@@ -138,7 +138,8 @@ static void on_connect(grpc_exec_ctx *exec_ctx, void *arg, grpc_endpoint *tcp,
static void test_no_op(void) {
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
grpc_tcp_server *s;
- GPR_ASSERT(GRPC_ERROR_NONE == grpc_tcp_server_create(NULL, NULL, &s));
+ GPR_ASSERT(GRPC_ERROR_NONE ==
+ grpc_tcp_server_create(&exec_ctx, NULL, NULL, &s));
grpc_tcp_server_unref(&exec_ctx, s);
grpc_exec_ctx_finish(&exec_ctx);
}
@@ -146,7 +147,8 @@ static void test_no_op(void) {
static void test_no_op_with_start(void) {
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
grpc_tcp_server *s;
- GPR_ASSERT(GRPC_ERROR_NONE == grpc_tcp_server_create(NULL, NULL, &s));
+ GPR_ASSERT(GRPC_ERROR_NONE ==
+ grpc_tcp_server_create(&exec_ctx, NULL, NULL, &s));
LOG_TEST("test_no_op_with_start");
grpc_tcp_server_start(&exec_ctx, s, NULL, 0, on_connect, NULL);
grpc_tcp_server_unref(&exec_ctx, s);
@@ -158,7 +160,8 @@ static void test_no_op_with_port(void) {
grpc_resolved_address resolved_addr;
struct sockaddr_in *addr = (struct sockaddr_in *)resolved_addr.addr;
grpc_tcp_server *s;
- GPR_ASSERT(GRPC_ERROR_NONE == grpc_tcp_server_create(NULL, NULL, &s));
+ GPR_ASSERT(GRPC_ERROR_NONE ==
+ grpc_tcp_server_create(&exec_ctx, NULL, NULL, &s));
LOG_TEST("test_no_op_with_port");
memset(&resolved_addr, 0, sizeof(resolved_addr));
@@ -178,7 +181,8 @@ static void test_no_op_with_port_and_start(void) {
grpc_resolved_address resolved_addr;
struct sockaddr_in *addr = (struct sockaddr_in *)resolved_addr.addr;
grpc_tcp_server *s;
- GPR_ASSERT(GRPC_ERROR_NONE == grpc_tcp_server_create(NULL, NULL, &s));
+ GPR_ASSERT(GRPC_ERROR_NONE ==
+ grpc_tcp_server_create(&exec_ctx, NULL, NULL, &s));
LOG_TEST("test_no_op_with_port_and_start");
int port;
@@ -241,7 +245,8 @@ static void test_connect(unsigned n) {
unsigned svr1_fd_count;
int svr1_port;
grpc_tcp_server *s;
- GPR_ASSERT(GRPC_ERROR_NONE == grpc_tcp_server_create(NULL, NULL, &s));
+ GPR_ASSERT(GRPC_ERROR_NONE ==
+ grpc_tcp_server_create(&exec_ctx, NULL, NULL, &s));
unsigned i;
server_weak_ref weak_ref;
server_weak_ref_init(&weak_ref);
diff --git a/test/core/security/secure_endpoint_test.c b/test/core/security/secure_endpoint_test.c
index 1d2bf73bb1..2262fde98d 100644
--- a/test/core/security/secure_endpoint_test.c
+++ b/test/core/security/secure_endpoint_test.c
@@ -56,7 +56,10 @@ static grpc_endpoint_test_fixture secure_endpoint_create_fixture_tcp_socketpair(
grpc_endpoint_test_fixture f;
grpc_endpoint_pair tcp;
- tcp = grpc_iomgr_create_endpoint_pair("fixture", slice_size);
+ grpc_resource_quota *resource_quota =
+ grpc_resource_quota_create("secure_endpoint_test");
+ tcp = grpc_iomgr_create_endpoint_pair("fixture", resource_quota, slice_size);
+ grpc_resource_quota_internal_unref(&exec_ctx, resource_quota);
grpc_endpoint_add_to_pollset(&exec_ctx, tcp.client, g_pollset);
grpc_endpoint_add_to_pollset(&exec_ctx, tcp.server, g_pollset);
diff --git a/test/core/surface/concurrent_connectivity_test.c b/test/core/surface/concurrent_connectivity_test.c
index f9f723baaa..f9f4675454 100644
--- a/test/core/surface/concurrent_connectivity_test.c
+++ b/test/core/surface/concurrent_connectivity_test.c
@@ -120,7 +120,7 @@ void bad_server_thread(void *vargs) {
struct sockaddr_storage *addr = (struct sockaddr_storage *)resolved_addr.addr;
int port;
grpc_tcp_server *s;
- grpc_error *error = grpc_tcp_server_create(NULL, NULL, &s);
+ grpc_error *error = grpc_tcp_server_create(&exec_ctx, NULL, NULL, &s);
GPR_ASSERT(error == GRPC_ERROR_NONE);
memset(&resolved_addr, 0, sizeof(resolved_addr));
addr->ss_family = AF_INET;
diff --git a/test/core/util/mock_endpoint.c b/test/core/util/mock_endpoint.c
index 13e0e918fb..2b041a4484 100644
--- a/test/core/util/mock_endpoint.c
+++ b/test/core/util/mock_endpoint.c
@@ -33,16 +33,20 @@
#include "test/core/util/mock_endpoint.h"
+#include <inttypes.h>
+
#include <grpc/support/alloc.h>
#include <grpc/support/string_util.h>
typedef struct grpc_mock_endpoint {
grpc_endpoint base;
gpr_mu mu;
+ int refs;
void (*on_write)(gpr_slice slice);
gpr_slice_buffer read_buffer;
gpr_slice_buffer *on_read_out;
grpc_closure *on_read;
+ grpc_resource_user resource_user;
} grpc_mock_endpoint;
static void me_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
@@ -74,6 +78,24 @@ static void me_add_to_pollset(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
static void me_add_to_pollset_set(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
grpc_pollset_set *pollset) {}
+static void unref(grpc_exec_ctx *exec_ctx, grpc_mock_endpoint *m) {
+ gpr_mu_lock(&m->mu);
+ if (0 == --m->refs) {
+ gpr_mu_unlock(&m->mu);
+ gpr_slice_buffer_destroy(&m->read_buffer);
+ grpc_resource_user_destroy(exec_ctx, &m->resource_user);
+ gpr_free(m);
+ } else {
+ gpr_mu_unlock(&m->mu);
+ }
+}
+
+static void me_finish_shutdown(grpc_exec_ctx *exec_ctx, void *me,
+ grpc_error *error) {
+ grpc_mock_endpoint *m = me;
+ unref(exec_ctx, m);
+}
+
static void me_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) {
grpc_mock_endpoint *m = (grpc_mock_endpoint *)ep;
gpr_mu_lock(&m->mu);
@@ -82,19 +104,25 @@ static void me_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) {
GRPC_ERROR_CREATE("Endpoint Shutdown"), NULL);
m->on_read = NULL;
}
+ grpc_resource_user_shutdown(exec_ctx, &m->resource_user,
+ grpc_closure_create(me_finish_shutdown, m));
gpr_mu_unlock(&m->mu);
}
static void me_destroy(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) {
grpc_mock_endpoint *m = (grpc_mock_endpoint *)ep;
- gpr_slice_buffer_destroy(&m->read_buffer);
- gpr_free(m);
+ unref(exec_ctx, m);
}
static char *me_get_peer(grpc_endpoint *ep) {
return gpr_strdup("fake:mock_endpoint");
}
+static grpc_resource_user *me_get_resource_user(grpc_endpoint *ep) {
+ grpc_mock_endpoint *m = (grpc_mock_endpoint *)ep;
+ return &m->resource_user;
+}
+
static grpc_workqueue *me_get_workqueue(grpc_endpoint *ep) { return NULL; }
static const grpc_endpoint_vtable vtable = {
@@ -105,12 +133,19 @@ static const grpc_endpoint_vtable vtable = {
me_add_to_pollset_set,
me_shutdown,
me_destroy,
+ me_get_resource_user,
me_get_peer,
};
-grpc_endpoint *grpc_mock_endpoint_create(void (*on_write)(gpr_slice slice)) {
+grpc_endpoint *grpc_mock_endpoint_create(void (*on_write)(gpr_slice slice),
+ grpc_resource_quota *resource_quota) {
grpc_mock_endpoint *m = gpr_malloc(sizeof(*m));
m->base.vtable = &vtable;
+ m->refs = 2;
+ char *name;
+ gpr_asprintf(&name, "mock_endpoint_%" PRIxPTR, (intptr_t)m);
+ grpc_resource_user_init(&m->resource_user, resource_quota, name);
+ gpr_free(name);
gpr_slice_buffer_init(&m->read_buffer);
gpr_mu_init(&m->mu);
m->on_write = on_write;
diff --git a/test/core/util/mock_endpoint.h b/test/core/util/mock_endpoint.h
index 051af9866b..b3a464ca01 100644
--- a/test/core/util/mock_endpoint.h
+++ b/test/core/util/mock_endpoint.h
@@ -36,7 +36,8 @@
#include "src/core/lib/iomgr/endpoint.h"
-grpc_endpoint *grpc_mock_endpoint_create(void (*on_write)(gpr_slice slice));
+grpc_endpoint *grpc_mock_endpoint_create(void (*on_write)(gpr_slice slice),
+ grpc_resource_quota *resource_quota);
void grpc_mock_endpoint_put_read(grpc_exec_ctx *exec_ctx,
grpc_endpoint *mock_endpoint, gpr_slice slice);
diff --git a/test/core/util/passthru_endpoint.c b/test/core/util/passthru_endpoint.c
index 7ed9e97bd6..ee6ef7da60 100644
--- a/test/core/util/passthru_endpoint.c
+++ b/test/core/util/passthru_endpoint.c
@@ -33,6 +33,8 @@
#include "test/core/util/passthru_endpoint.h"
+#include <inttypes.h>
+
#include <grpc/support/alloc.h>
#include <grpc/support/string_util.h>
@@ -44,6 +46,7 @@ typedef struct {
gpr_slice_buffer read_buffer;
gpr_slice_buffer *on_read_out;
grpc_closure *on_read;
+ grpc_resource_user resource_user;
} half;
struct passthru_endpoint {
@@ -122,7 +125,8 @@ static void me_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) {
gpr_mu_unlock(&m->parent->mu);
}
-static void me_destroy(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) {
+static void me_really_destroy(grpc_exec_ctx *exec_ctx, void *ep,
+ grpc_error *error) {
passthru_endpoint *p = ((half *)ep)->parent;
gpr_mu_lock(&p->mu);
if (0 == --p->halves) {
@@ -136,12 +140,23 @@ static void me_destroy(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) {
}
}
+static void me_destroy(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) {
+ half *m = (half *)ep;
+ grpc_resource_user_shutdown(exec_ctx, &m->resource_user,
+ grpc_closure_create(me_really_destroy, m));
+}
+
static char *me_get_peer(grpc_endpoint *ep) {
return gpr_strdup("fake:mock_endpoint");
}
static grpc_workqueue *me_get_workqueue(grpc_endpoint *ep) { return NULL; }
+static grpc_resource_user *me_get_resource_user(grpc_endpoint *ep) {
+ half *m = (half *)ep;
+ return &m->resource_user;
+}
+
static const grpc_endpoint_vtable vtable = {
me_read,
me_write,
@@ -150,23 +165,32 @@ static const grpc_endpoint_vtable vtable = {
me_add_to_pollset_set,
me_shutdown,
me_destroy,
+ me_get_resource_user,
me_get_peer,
};
-static void half_init(half *m, passthru_endpoint *parent) {
+static void half_init(half *m, passthru_endpoint *parent,
+ grpc_resource_quota *resource_quota,
+ const char *half_name) {
m->base.vtable = &vtable;
m->parent = parent;
gpr_slice_buffer_init(&m->read_buffer);
m->on_read = NULL;
+ char *name;
+ gpr_asprintf(&name, "passthru_endpoint_%s_%" PRIxPTR, half_name,
+ (intptr_t)parent);
+ grpc_resource_user_init(&m->resource_user, resource_quota, name);
+ gpr_free(name);
}
void grpc_passthru_endpoint_create(grpc_endpoint **client,
- grpc_endpoint **server) {
+ grpc_endpoint **server,
+ grpc_resource_quota *resource_quota) {
passthru_endpoint *m = gpr_malloc(sizeof(*m));
m->halves = 2;
m->shutdown = 0;
- half_init(&m->client, m);
- half_init(&m->server, m);
+ half_init(&m->client, m, resource_quota, "client");
+ half_init(&m->server, m, resource_quota, "server");
gpr_mu_init(&m->mu);
*client = &m->client.base;
*server = &m->server.base;
diff --git a/test/core/util/passthru_endpoint.h b/test/core/util/passthru_endpoint.h
index aa1d3a1763..b81ac5571c 100644
--- a/test/core/util/passthru_endpoint.h
+++ b/test/core/util/passthru_endpoint.h
@@ -37,6 +37,7 @@
#include "src/core/lib/iomgr/endpoint.h"
void grpc_passthru_endpoint_create(grpc_endpoint **client,
- grpc_endpoint **server);
+ grpc_endpoint **server,
+ grpc_resource_quota *resource_quota);
#endif
diff --git a/test/core/util/port_server_client.c b/test/core/util/port_server_client.c
index a5c8c49650..b2342feeb4 100644
--- a/test/core/util/port_server_client.c
+++ b/test/core/util/port_server_client.c
@@ -99,9 +99,12 @@ void grpc_free_port_using_server(char *server, int port) {
req.http.path = path;
grpc_httpcli_context_init(&context);
- grpc_httpcli_get(&exec_ctx, &context, &pr.pops, &req,
+ grpc_resource_quota *resource_quota =
+ grpc_resource_quota_create("port_server_client/free");
+ grpc_httpcli_get(&exec_ctx, &context, &pr.pops, resource_quota, &req,
GRPC_TIMEOUT_SECONDS_TO_DEADLINE(10),
grpc_closure_create(freed_port_from_server, &pr), &rsp);
+ grpc_resource_quota_internal_unref(&exec_ctx, resource_quota);
gpr_mu_lock(pr.mu);
while (!pr.done) {
grpc_pollset_worker *worker = NULL;
@@ -167,10 +170,13 @@ static void got_port_from_server(grpc_exec_ctx *exec_ctx, void *arg,
req.http.path = "/get";
grpc_http_response_destroy(&pr->response);
memset(&pr->response, 0, sizeof(pr->response));
- grpc_httpcli_get(exec_ctx, pr->ctx, &pr->pops, &req,
+ grpc_resource_quota *resource_quota =
+ grpc_resource_quota_create("port_server_client/pick_retry");
+ grpc_httpcli_get(exec_ctx, pr->ctx, &pr->pops, resource_quota, &req,
GRPC_TIMEOUT_SECONDS_TO_DEADLINE(10),
grpc_closure_create(got_port_from_server, pr),
&pr->response);
+ grpc_resource_quota_internal_unref(exec_ctx, resource_quota);
return;
}
GPR_ASSERT(response);
@@ -211,9 +217,13 @@ int grpc_pick_port_using_server(char *server) {
req.http.path = "/get";
grpc_httpcli_context_init(&context);
- grpc_httpcli_get(
- &exec_ctx, &context, &pr.pops, &req, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(10),
- grpc_closure_create(got_port_from_server, &pr), &pr.response);
+ grpc_resource_quota *resource_quota =
+ grpc_resource_quota_create("port_server_client/pick");
+ grpc_httpcli_get(&exec_ctx, &context, &pr.pops, resource_quota, &req,
+ GRPC_TIMEOUT_SECONDS_TO_DEADLINE(10),
+ grpc_closure_create(got_port_from_server, &pr),
+ &pr.response);
+ grpc_resource_quota_internal_unref(&exec_ctx, resource_quota);
grpc_exec_ctx_finish(&exec_ctx);
gpr_mu_lock(pr.mu);
while (pr.port == -1) {
diff --git a/test/core/util/test_tcp_server.c b/test/core/util/test_tcp_server.c
index 9ac97413d4..16df91d968 100644
--- a/test/core/util/test_tcp_server.c
+++ b/test/core/util/test_tcp_server.c
@@ -75,8 +75,8 @@ void test_tcp_server_start(test_tcp_server *server, int port) {
addr->sin_port = htons((uint16_t)port);
memset(&addr->sin_addr, 0, sizeof(addr->sin_addr));
- grpc_error *error = grpc_tcp_server_create(&server->shutdown_complete, NULL,
- &server->tcp_server);
+ grpc_error *error = grpc_tcp_server_create(
+ &exec_ctx, &server->shutdown_complete, NULL, &server->tcp_server);
GPR_ASSERT(error == GRPC_ERROR_NONE);
error =
grpc_tcp_server_add_port(server->tcp_server, &resolved_addr, &port_added);
diff --git a/test/cpp/end2end/end2end_test.cc b/test/cpp/end2end/end2end_test.cc
index 7af0fb997e..feadabd865 100644
--- a/test/cpp/end2end/end2end_test.cc
+++ b/test/cpp/end2end/end2end_test.cc
@@ -37,6 +37,7 @@
#include <grpc++/channel.h>
#include <grpc++/client_context.h>
#include <grpc++/create_channel.h>
+#include <grpc++/resource_quota.h>
#include <grpc++/security/auth_metadata_processor.h>
#include <grpc++/security/credentials.h>
#include <grpc++/security/server_credentials.h>
@@ -240,6 +241,7 @@ class End2endTest : public ::testing::TestWithParam<TestScenario> {
server_address_ << "127.0.0.1:" << port;
// Setup server
ServerBuilder builder;
+ ConfigureServerBuilder(&builder);
auto server_creds = GetServerCredentials(GetParam().credentials_type);
if (GetParam().credentials_type != kInsecureCredentialsType) {
server_creds->SetAuthMetadataProcessor(processor);
@@ -247,13 +249,16 @@ class End2endTest : public ::testing::TestWithParam<TestScenario> {
builder.AddListeningPort(server_address_.str(), server_creds);
builder.RegisterService(&service_);
builder.RegisterService("foo.test.youtube.com", &special_service_);
- builder.SetMaxMessageSize(
- kMaxMessageSize_); // For testing max message size.
builder.RegisterService(&dup_pkg_service_);
server_ = builder.BuildAndStart();
is_server_started_ = true;
}
+ virtual void ConfigureServerBuilder(ServerBuilder* builder) {
+ builder->SetMaxMessageSize(
+ kMaxMessageSize_); // For testing max message size.
+ }
+
void ResetChannel() {
if (!is_server_started_) {
StartServer(std::shared_ptr<AuthMetadataProcessor>());
@@ -1476,6 +1481,32 @@ TEST_P(SecureEnd2endTest, ClientAuthContext) {
}
}
+class ResourceQuotaEnd2endTest : public End2endTest {
+ public:
+ ResourceQuotaEnd2endTest()
+ : server_resource_quota_("server_resource_quota") {}
+
+ virtual void ConfigureServerBuilder(ServerBuilder* builder) GRPC_OVERRIDE {
+ builder->SetResourceQuota(server_resource_quota_);
+ }
+
+ private:
+ ResourceQuota server_resource_quota_;
+};
+
+TEST_P(ResourceQuotaEnd2endTest, SimpleRequest) {
+ ResetStub();
+
+ EchoRequest request;
+ EchoResponse response;
+ request.set_message("Hello");
+
+ ClientContext context;
+ Status s = stub_->Echo(&context, request, &response);
+ EXPECT_EQ(response.message(), request.message());
+ EXPECT_TRUE(s.ok());
+}
+
std::vector<TestScenario> CreateTestScenarios(bool use_proxy,
bool test_insecure,
bool test_secure) {
@@ -1513,6 +1544,10 @@ INSTANTIATE_TEST_CASE_P(SecureEnd2end, SecureEnd2endTest,
::testing::ValuesIn(CreateTestScenarios(false, false,
true)));
+INSTANTIATE_TEST_CASE_P(ResourceQuotaEnd2end, ResourceQuotaEnd2endTest,
+ ::testing::ValuesIn(CreateTestScenarios(false, true,
+ true)));
+
} // namespace
} // namespace testing
} // namespace grpc
diff --git a/test/cpp/qps/client.h b/test/cpp/qps/client.h
index 5fb87b2782..9983c8a7b0 100644
--- a/test/cpp/qps/client.h
+++ b/test/cpp/qps/client.h
@@ -36,6 +36,7 @@
#include <condition_variable>
#include <mutex>
+#include <unordered_map>
#include <vector>
#include <grpc++/channel.h>
@@ -114,19 +115,37 @@ class ClientRequestCreator<ByteBuffer> {
class HistogramEntry GRPC_FINAL {
public:
- HistogramEntry() : used_(false) {}
- bool used() const { return used_; }
+ HistogramEntry() : value_used_(false), status_used_(false) {}
+ bool value_used() const { return value_used_; }
double value() const { return value_; }
void set_value(double v) {
- used_ = true;
+ value_used_ = true;
value_ = v;
}
+ bool status_used() const { return status_used_; }
+ int status() const { return status_; }
+ void set_status(int status) {
+ status_used_ = true;
+ status_ = status;
+ }
private:
- bool used_;
+ bool value_used_;
double value_;
+ bool status_used_;
+ int status_;
};
+typedef std::unordered_map<int, int64_t> StatusHistogram;
+
+inline void MergeStatusHistogram(const StatusHistogram& from,
+ StatusHistogram* to) {
+ for (StatusHistogram::const_iterator it = from.begin(); it != from.end();
+ ++it) {
+ (*to)[it->first] += it->second;
+ }
+}
+
class Client {
public:
Client()
@@ -139,6 +158,7 @@ class Client {
ClientStats Mark(bool reset) {
Histogram latencies;
+ StatusHistogram statuses;
UsageTimer::Result timer_result;
MaybeStartRequests();
@@ -146,27 +166,36 @@ class Client {
// avoid std::vector for old compilers that expect a copy constructor
if (reset) {
Histogram* to_merge = new Histogram[threads_.size()];
+ StatusHistogram* to_merge_status = new StatusHistogram[threads_.size()];
+
for (size_t i = 0; i < threads_.size(); i++) {
- threads_[i]->BeginSwap(&to_merge[i]);
+ threads_[i]->BeginSwap(&to_merge[i], &to_merge_status[i]);
}
std::unique_ptr<UsageTimer> timer(new UsageTimer);
timer_.swap(timer);
for (size_t i = 0; i < threads_.size(); i++) {
- threads_[i]->EndSwap();
latencies.Merge(to_merge[i]);
+ MergeStatusHistogram(to_merge_status[i], &statuses);
}
delete[] to_merge;
+ delete[] to_merge_status;
timer_result = timer->Mark();
} else {
// merge snapshots of each thread histogram
for (size_t i = 0; i < threads_.size(); i++) {
- threads_[i]->MergeStatsInto(&latencies);
+ threads_[i]->MergeStatsInto(&latencies, &statuses);
}
timer_result = timer_->Mark();
}
ClientStats stats;
latencies.FillProto(stats.mutable_latencies());
+ for (StatusHistogram::const_iterator it = statuses.begin();
+ it != statuses.end(); ++it) {
+ RequestResultCount* rrc = stats.add_request_results();
+ rrc->set_status_code(it->first);
+ rrc->set_count(it->second);
+ }
stats.set_time_elapsed(timer_result.wall);
stats.set_time_system(timer_result.system);
stats.set_time_user(timer_result.user);
@@ -258,16 +287,16 @@ class Client {
~Thread() { impl_.join(); }
- void BeginSwap(Histogram* n) {
+ void BeginSwap(Histogram* n, StatusHistogram* s) {
std::lock_guard<std::mutex> g(mu_);
n->Swap(&histogram_);
+ s->swap(statuses_);
}
- void EndSwap() {}
-
- void MergeStatsInto(Histogram* hist) {
+ void MergeStatsInto(Histogram* hist, StatusHistogram* s) {
std::unique_lock<std::mutex> g(mu_);
hist->Merge(histogram_);
+ MergeStatusHistogram(statuses_, s);
}
private:
@@ -288,9 +317,12 @@ class Client {
const bool thread_still_ok = client_->ThreadFunc(&entry, idx_);
// lock, update histogram if needed and see if we're done
std::lock_guard<std::mutex> g(mu_);
- if (entry.used()) {
+ if (entry.value_used()) {
histogram_.Add(entry.value());
}
+ if (entry.status_used()) {
+ statuses_[entry.status()]++;
+ }
if (!thread_still_ok) {
gpr_log(GPR_ERROR, "Finishing client thread due to RPC error");
}
@@ -304,6 +336,7 @@ class Client {
std::mutex mu_;
Histogram histogram_;
+ StatusHistogram statuses_;
Client* client_;
const size_t idx_;
std::thread impl_;
diff --git a/test/cpp/qps/client_async.cc b/test/cpp/qps/client_async.cc
index 081114859c..4d36a6ba42 100644
--- a/test/cpp/qps/client_async.cc
+++ b/test/cpp/qps/client_async.cc
@@ -83,7 +83,7 @@ class ClientRpcContextUnaryImpl : public ClientRpcContext {
BenchmarkService::Stub*, grpc::ClientContext*, const RequestType&,
CompletionQueue*)>
start_req,
- std::function<void(grpc::Status, ResponseType*)> on_done)
+ std::function<void(grpc::Status, ResponseType*, HistogramEntry*)> on_done)
: context_(),
stub_(stub),
cq_(nullptr),
@@ -113,7 +113,7 @@ class ClientRpcContextUnaryImpl : public ClientRpcContext {
return true;
case State::RESP_DONE:
entry->set_value((UsageTimer::Now() - start_) * 1e9);
- callback_(status_, &response_);
+ callback_(status_, &response_, entry);
next_state_ = State::INVALID;
return false;
default:
@@ -135,7 +135,7 @@ class ClientRpcContextUnaryImpl : public ClientRpcContext {
ResponseType response_;
enum State { INVALID, READY, RESP_DONE };
State next_state_;
- std::function<void(grpc::Status, ResponseType*)> callback_;
+ std::function<void(grpc::Status, ResponseType*, HistogramEntry*)> callback_;
std::function<gpr_timespec()> next_issue_;
std::function<std::unique_ptr<grpc::ClientAsyncResponseReader<ResponseType>>(
BenchmarkService::Stub*, grpc::ClientContext*, const RequestType&,
@@ -290,7 +290,10 @@ class AsyncUnaryClient GRPC_FINAL
~AsyncUnaryClient() GRPC_OVERRIDE {}
private:
- static void CheckDone(grpc::Status s, SimpleResponse* response) {}
+ static void CheckDone(grpc::Status s, SimpleResponse* response,
+ HistogramEntry* entry) {
+ entry->set_status(s.error_code());
+ }
static std::unique_ptr<grpc::ClientAsyncResponseReader<SimpleResponse>>
StartReq(BenchmarkService::Stub* stub, grpc::ClientContext* ctx,
const SimpleRequest& request, CompletionQueue* cq) {
diff --git a/test/cpp/qps/client_sync.cc b/test/cpp/qps/client_sync.cc
index 0ccf4e270b..f61e80d76b 100644
--- a/test/cpp/qps/client_sync.cc
+++ b/test/cpp/qps/client_sync.cc
@@ -130,11 +130,8 @@ class SynchronousUnaryClient GRPC_FINAL : public SynchronousClient {
grpc::Status s =
stub->UnaryCall(&context, request_, &responses_[thread_idx]);
entry->set_value((UsageTimer::Now() - start) * 1e9);
- if (!s.ok()) {
- gpr_log(GPR_ERROR, "RPC error: %d: %s", s.error_code(),
- s.error_message().c_str());
- }
- return s.ok();
+ entry->set_status(s.error_code());
+ return true;
}
};
diff --git a/test/cpp/qps/driver.cc b/test/cpp/qps/driver.cc
index 6c675e3483..a440341ccf 100644
--- a/test/cpp/qps/driver.cc
+++ b/test/cpp/qps/driver.cc
@@ -132,7 +132,8 @@ static void postprocess_scenario_result(ScenarioResult* result) {
Histogram histogram;
histogram.MergeProto(result->latencies());
- auto qps = histogram.Count() / average(result->client_stats(), WallTime);
+ auto time_estimate = average(result->client_stats(), WallTime);
+ auto qps = histogram.Count() / time_estimate;
auto qps_per_server_core = qps / sum(result->server_cores(), Cores);
result->mutable_summary()->set_qps(qps);
@@ -157,6 +158,23 @@ static void postprocess_scenario_result(ScenarioResult* result) {
result->mutable_summary()->set_server_user_time(server_user_time);
result->mutable_summary()->set_client_system_time(client_system_time);
result->mutable_summary()->set_client_user_time(client_user_time);
+
+ if (result->request_results_size() > 0) {
+ int64_t successes = 0;
+ int64_t failures = 0;
+ for (int i = 0; i < result->request_results_size(); i++) {
+ RequestResultCount rrc = result->request_results(i);
+ if (rrc.status_code() == 0) {
+ successes += rrc.count();
+ } else {
+ failures += rrc.count();
+ }
+ }
+ result->mutable_summary()->set_successful_requests_per_second(
+ successes / time_estimate);
+ result->mutable_summary()->set_failed_requests_per_second(failures /
+ time_estimate);
+ }
}
// Namespace for classes and functions used only in RunScenario
@@ -444,6 +462,7 @@ std::unique_ptr<ScenarioResult> RunScenario(
// Finish a run
std::unique_ptr<ScenarioResult> result(new ScenarioResult);
Histogram merged_latencies;
+ std::unordered_map<int, int64_t> merged_statuses;
gpr_log(GPR_INFO, "Finishing clients");
for (size_t i = 0; i < num_clients; i++) {
@@ -462,6 +481,10 @@ std::unique_ptr<ScenarioResult> RunScenario(
gpr_log(GPR_INFO, "Received final status from client %zu", i);
const auto& stats = client_status.stats();
merged_latencies.MergeProto(stats.latencies());
+ for (int i = 0; i < stats.request_results_size(); i++) {
+ merged_statuses[stats.request_results(i).status_code()] +=
+ stats.request_results(i).count();
+ }
result->add_client_stats()->CopyFrom(stats);
// That final status should be the last message on the client stream
GPR_ASSERT(!client->stream->Read(&client_status));
@@ -481,6 +504,12 @@ std::unique_ptr<ScenarioResult> RunScenario(
delete[] clients;
merged_latencies.FillProto(result->mutable_latencies());
+ for (std::unordered_map<int, int64_t>::iterator it = merged_statuses.begin();
+ it != merged_statuses.end(); ++it) {
+ RequestResultCount* rrc = result->add_request_results();
+ rrc->set_status_code(it->first);
+ rrc->set_count(it->second);
+ }
gpr_log(GPR_INFO, "Finishing servers");
for (size_t i = 0; i < num_servers; i++) {
diff --git a/test/cpp/qps/report.cc b/test/cpp/qps/report.cc
index 2ec7d8676c..41617e968a 100644
--- a/test/cpp/qps/report.cc
+++ b/test/cpp/qps/report.cc
@@ -73,6 +73,12 @@ void CompositeReporter::ReportTimes(const ScenarioResult& result) {
void GprLogReporter::ReportQPS(const ScenarioResult& result) {
gpr_log(GPR_INFO, "QPS: %.1f", result.summary().qps());
+ if (result.summary().failed_requests_per_second() > 0) {
+ gpr_log(GPR_INFO, "failed requests/second: %.1f",
+ result.summary().failed_requests_per_second());
+ gpr_log(GPR_INFO, "successful requests/second: %.1f",
+ result.summary().successful_requests_per_second());
+ }
}
void GprLogReporter::ReportQPSPerCore(const ScenarioResult& result) {
diff --git a/test/cpp/qps/server_async.cc b/test/cpp/qps/server_async.cc
index 2fcc64819b..bc4c896d83 100644
--- a/test/cpp/qps/server_async.cc
+++ b/test/cpp/qps/server_async.cc
@@ -38,6 +38,7 @@
#include <thread>
#include <grpc++/generic/async_generic_service.h>
+#include <grpc++/resource_quota.h>
#include <grpc++/security/server_credentials.h>
#include <grpc++/server.h>
#include <grpc++/server_builder.h>
@@ -95,6 +96,11 @@ class AsyncQpsServerTest GRPC_FINAL : public grpc::testing::Server {
srv_cqs_.emplace_back(builder.AddCompletionQueue());
}
+ if (config.resource_quota_size() > 0) {
+ builder.SetResourceQuota(ResourceQuota("AsyncQpsServerTest")
+ .Resize(config.resource_quota_size()));
+ }
+
server_ = builder.BuildAndStart();
using namespace std::placeholders;
diff --git a/test/cpp/qps/server_sync.cc b/test/cpp/qps/server_sync.cc
index 0caed0ab49..07f48e2644 100644
--- a/test/cpp/qps/server_sync.cc
+++ b/test/cpp/qps/server_sync.cc
@@ -31,6 +31,7 @@
*
*/
+#include <grpc++/resource_quota.h>
#include <grpc++/security/server_credentials.h>
#include <grpc++/server.h>
#include <grpc++/server_builder.h>
@@ -91,6 +92,11 @@ class SynchronousServer GRPC_FINAL : public grpc::testing::Server {
Server::CreateServerCredentials(config));
gpr_free(server_address);
+ if (config.resource_quota_size() > 0) {
+ builder.SetResourceQuota(ResourceQuota("AsyncQpsServerTest")
+ .Resize(config.resource_quota_size()));
+ }
+
builder.RegisterService(&service_);
impl_ = builder.BuildAndStart();
diff --git a/tools/doxygen/Doxyfile.c++ b/tools/doxygen/Doxyfile.c++
index 4b0be37e09..00f970a4cb 100644
--- a/tools/doxygen/Doxyfile.c++
+++ b/tools/doxygen/Doxyfile.c++
@@ -787,6 +787,7 @@ include/grpc++/impl/sync_no_cxx11.h \
include/grpc++/impl/thd.h \
include/grpc++/impl/thd_cxx11.h \
include/grpc++/impl/thd_no_cxx11.h \
+include/grpc++/resource_quota.h \
include/grpc++/security/auth_context.h \
include/grpc++/security/auth_metadata_processor.h \
include/grpc++/security/credentials.h \
diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal
index e266e15481..252bdb7ed1 100644
--- a/tools/doxygen/Doxyfile.c++.internal
+++ b/tools/doxygen/Doxyfile.c++.internal
@@ -787,6 +787,7 @@ include/grpc++/impl/sync_no_cxx11.h \
include/grpc++/impl/thd.h \
include/grpc++/impl/thd_cxx11.h \
include/grpc++/impl/thd_no_cxx11.h \
+include/grpc++/resource_quota.h \
include/grpc++/security/auth_context.h \
include/grpc++/security/auth_metadata_processor.h \
include/grpc++/security/credentials.h \
@@ -882,6 +883,7 @@ src/cpp/common/channel_arguments.cc \
src/cpp/common/channel_filter.cc \
src/cpp/common/completion_queue_cc.cc \
src/cpp/common/core_codegen.cc \
+src/cpp/common/resource_quota_cc.cc \
src/cpp/common/rpc_method.cc \
src/cpp/server/async_generic_service.cc \
src/cpp/server/create_default_thread_pool.cc \
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index 8db1a79be0..e83298766f 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -828,6 +828,7 @@ 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 \
@@ -836,6 +837,7 @@ 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/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_uv.h \
@@ -1003,6 +1005,7 @@ src/core/lib/iomgr/pollset_windows.c \
src/core/lib/iomgr/resolve_address_posix.c \
src/core/lib/iomgr/resolve_address_uv.c \
src/core/lib/iomgr/resolve_address_windows.c \
+src/core/lib/iomgr/resource_quota.c \
src/core/lib/iomgr/sockaddr_utils.c \
src/core/lib/iomgr/socket_utils_common_posix.c \
src/core/lib/iomgr/socket_utils_linux.c \
diff --git a/tools/run_tests/performance/scenario_config.py b/tools/run_tests/performance/scenario_config.py
index 4a4ce4537d..4e4c16642b 100644
--- a/tools/run_tests/performance/scenario_config.py
+++ b/tools/run_tests/performance/scenario_config.py
@@ -114,7 +114,8 @@ def _ping_pong_scenario(name, rpc_type,
warmup_seconds=WARMUP_SECONDS,
categories=DEFAULT_CATEGORIES,
channels=None,
- outstanding=None):
+ outstanding=None,
+ resource_quota_size=None):
"""Creates a basic ping pong scenario."""
scenario = {
'name': name,
@@ -141,6 +142,8 @@ def _ping_pong_scenario(name, rpc_type,
'warmup_seconds': warmup_seconds,
'benchmark_seconds': BENCHMARK_SECONDS
}
+ if resource_quota_size:
+ scenario['server_config']['resource_quota_size'] = resource_quota_size
if use_generic_payload:
if server_type != 'ASYNC_GENERIC_SERVER':
raise Exception('Use ASYNC_GENERIC_SERVER for generic payload.')
@@ -257,6 +260,16 @@ class CXXLanguage:
secure=secure,
categories=smoketest_categories+[SCALABLE])
+ yield _ping_pong_scenario(
+ 'cpp_protobuf_%s_%s_qps_unconstrained_%s_500kib_resource_quota' % (synchronicity, rpc_type, secstr),
+ rpc_type=rpc_type.upper(),
+ client_type='%s_CLIENT' % synchronicity.upper(),
+ server_type='%s_SERVER' % synchronicity.upper(),
+ unconstrained_client=synchronicity,
+ secure=secure,
+ categories=smoketest_categories+[SCALABLE],
+ resource_quota_size=500*1024)
+
for channels in geometric_progression(1, 20000, math.sqrt(10)):
for outstanding in geometric_progression(1, 200000, math.sqrt(10)):
if synchronicity == 'sync' and outstanding > 1200: continue
diff --git a/tools/run_tests/sources_and_headers.json b/tools/run_tests/sources_and_headers.json
index d7d6911c0e..a137848c97 100644
--- a/tools/run_tests/sources_and_headers.json
+++ b/tools/run_tests/sources_and_headers.json
@@ -1731,6 +1731,23 @@
"headers": [],
"is_filegroup": false,
"language": "c",
+ "name": "resource_quota_test",
+ "src": [
+ "test/core/iomgr/resource_quota_test.c"
+ ],
+ "third_party": false,
+ "type": "target"
+ },
+ {
+ "deps": [
+ "gpr",
+ "gpr_test_util",
+ "grpc",
+ "grpc_test_util"
+ ],
+ "headers": [],
+ "is_filegroup": false,
+ "language": "c",
"name": "secure_channel_create_test",
"src": [
"test/core/surface/secure_channel_create_test.c"
@@ -6174,6 +6191,7 @@
"test/core/end2end/tests/registered_call.c",
"test/core/end2end/tests/request_with_flags.c",
"test/core/end2end/tests/request_with_payload.c",
+ "test/core/end2end/tests/resource_quota_server.c",
"test/core/end2end/tests/server_finishes_request.c",
"test/core/end2end/tests/shutdown_finishes_calls.c",
"test/core/end2end/tests/shutdown_finishes_tags.c",
@@ -6239,6 +6257,7 @@
"test/core/end2end/tests/registered_call.c",
"test/core/end2end/tests/request_with_flags.c",
"test/core/end2end/tests/request_with_payload.c",
+ "test/core/end2end/tests/resource_quota_server.c",
"test/core/end2end/tests/server_finishes_request.c",
"test/core/end2end/tests/shutdown_finishes_calls.c",
"test/core/end2end/tests/shutdown_finishes_tags.c",
@@ -6538,6 +6557,7 @@
"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",
@@ -6546,6 +6566,7 @@
"src/core/lib/iomgr/socket_utils_posix.h",
"src/core/lib/iomgr/socket_windows.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_uv.h",
@@ -6686,6 +6707,8 @@
"src/core/lib/iomgr/resolve_address_posix.c",
"src/core/lib/iomgr/resolve_address_uv.c",
"src/core/lib/iomgr/resolve_address_windows.c",
+ "src/core/lib/iomgr/resource_quota.c",
+ "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.c",
@@ -6702,6 +6725,7 @@
"src/core/lib/iomgr/socket_windows.h",
"src/core/lib/iomgr/tcp_client.h",
"src/core/lib/iomgr/tcp_client_posix.c",
+ "src/core/lib/iomgr/tcp_client_posix.h",
"src/core/lib/iomgr/tcp_client_uv.c",
"src/core/lib/iomgr/tcp_client_windows.c",
"src/core/lib/iomgr/tcp_posix.c",
@@ -7403,6 +7427,7 @@
"include/grpc++/impl/thd.h",
"include/grpc++/impl/thd_cxx11.h",
"include/grpc++/impl/thd_no_cxx11.h",
+ "include/grpc++/resource_quota.h",
"include/grpc++/security/auth_context.h",
"include/grpc++/security/auth_metadata_processor.h",
"include/grpc++/security/credentials.h",
@@ -7459,6 +7484,7 @@
"include/grpc++/impl/thd.h",
"include/grpc++/impl/thd_cxx11.h",
"include/grpc++/impl/thd_no_cxx11.h",
+ "include/grpc++/resource_quota.h",
"include/grpc++/security/auth_context.h",
"include/grpc++/security/auth_metadata_processor.h",
"include/grpc++/security/credentials.h",
@@ -7492,6 +7518,7 @@
"src/cpp/common/channel_filter.h",
"src/cpp/common/completion_queue_cc.cc",
"src/cpp/common/core_codegen.cc",
+ "src/cpp/common/resource_quota_cc.cc",
"src/cpp/common/rpc_method.cc",
"src/cpp/server/async_generic_service.cc",
"src/cpp/server/create_default_thread_pool.cc",
diff --git a/tools/run_tests/tests.json b/tools/run_tests/tests.json
index e5b406db12..09cf89d5e7 100644
--- a/tools/run_tests/tests.json
+++ b/tools/run_tests/tests.json
@@ -1773,6 +1773,28 @@
"posix",
"windows"
],
+ "cpu_cost": 30,
+ "exclude_configs": [],
+ "exclude_iomgrs": [],
+ "flaky": false,
+ "gtest": false,
+ "language": "c",
+ "name": "resource_quota_test",
+ "platforms": [
+ "linux",
+ "mac",
+ "posix",
+ "windows"
+ ]
+ },
+ {
+ "args": [],
+ "ci_platforms": [
+ "linux",
+ "mac",
+ "posix",
+ "windows"
+ ],
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [],
@@ -5112,7 +5134,7 @@
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [],
- "flaky": false,
+ "flaky": true,
"language": "c",
"name": "h2_census_test",
"platforms": [
@@ -5630,6 +5652,29 @@
},
{
"args": [
+ "resource_quota_server"
+ ],
+ "ci_platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_census_test",
+ "platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"server_finishes_request"
],
"ci_platforms": [
@@ -6126,7 +6171,7 @@
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [],
- "flaky": false,
+ "flaky": true,
"language": "c",
"name": "h2_compress_test",
"platforms": [
@@ -6644,6 +6689,29 @@
},
{
"args": [
+ "resource_quota_server"
+ ],
+ "ci_platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_compress_test",
+ "platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"server_finishes_request"
],
"ci_platforms": [
@@ -7140,7 +7208,7 @@
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [],
- "flaky": false,
+ "flaky": true,
"language": "c",
"name": "h2_fake_resolver_test",
"platforms": [
@@ -7658,6 +7726,29 @@
},
{
"args": [
+ "resource_quota_server"
+ ],
+ "ci_platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_fake_resolver_test",
+ "platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"server_finishes_request"
],
"ci_platforms": [
@@ -8141,7 +8232,7 @@
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [],
- "flaky": false,
+ "flaky": true,
"language": "c",
"name": "h2_fakesec_test",
"platforms": [
@@ -8637,6 +8728,28 @@
},
{
"args": [
+ "resource_quota_server"
+ ],
+ "ci_platforms": [
+ "windows",
+ "linux",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_fakesec_test",
+ "platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"server_finishes_request"
],
"ci_platforms": [
@@ -9548,6 +9661,29 @@
},
{
"args": [
+ "resource_quota_server"
+ ],
+ "ci_platforms": [
+ "linux",
+ "mac",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [
+ "uv"
+ ],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_fd_test",
+ "platforms": [
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"server_finishes_request"
],
"ci_platforms": [
@@ -10021,7 +10157,7 @@
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [],
- "flaky": false,
+ "flaky": true,
"language": "c",
"name": "h2_full_test",
"platforms": [
@@ -10539,6 +10675,29 @@
},
{
"args": [
+ "resource_quota_server"
+ ],
+ "ci_platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_full_test",
+ "platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"server_finishes_request"
],
"ci_platforms": [
@@ -10984,7 +11143,7 @@
"exclude_iomgrs": [
"uv"
],
- "flaky": false,
+ "flaky": true,
"language": "c",
"name": "h2_full+pipe_test",
"platforms": [
@@ -11411,6 +11570,25 @@
},
{
"args": [
+ "resource_quota_server"
+ ],
+ "ci_platforms": [
+ "linux"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [
+ "uv"
+ ],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_full+pipe_test",
+ "platforms": [
+ "linux"
+ ]
+ },
+ {
+ "args": [
"server_finishes_request"
],
"ci_platforms": [
@@ -11871,7 +12049,7 @@
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [],
- "flaky": false,
+ "flaky": true,
"language": "c",
"name": "h2_full+trace_test",
"platforms": [
@@ -12343,6 +12521,29 @@
},
{
"args": [
+ "resource_quota_server"
+ ],
+ "ci_platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_full+trace_test",
+ "platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"server_finishes_request"
],
"ci_platforms": [
@@ -12850,7 +13051,7 @@
"exclude_iomgrs": [
"uv"
],
- "flaky": false,
+ "flaky": true,
"language": "c",
"name": "h2_http_proxy_test",
"platforms": [
@@ -13390,6 +13591,30 @@
},
{
"args": [
+ "resource_quota_server"
+ ],
+ "ci_platforms": [
+ "windows",
+ "linux",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [
+ "uv"
+ ],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_http_proxy_test",
+ "platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"server_finishes_request"
],
"ci_platforms": [
@@ -13895,7 +14120,7 @@
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [],
- "flaky": false,
+ "flaky": true,
"language": "c",
"name": "h2_load_reporting_test",
"platforms": [
@@ -14413,6 +14638,29 @@
},
{
"args": [
+ "resource_quota_server"
+ ],
+ "ci_platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_load_reporting_test",
+ "platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"server_finishes_request"
],
"ci_platforms": [
@@ -14920,7 +15168,7 @@
"exclude_iomgrs": [
"uv"
],
- "flaky": false,
+ "flaky": true,
"language": "c",
"name": "h2_oauth2_test",
"platforms": [
@@ -15460,6 +15708,30 @@
},
{
"args": [
+ "resource_quota_server"
+ ],
+ "ci_platforms": [
+ "windows",
+ "linux",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [
+ "uv"
+ ],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_oauth2_test",
+ "platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"server_finishes_request"
],
"ci_platforms": [
@@ -15928,7 +16200,7 @@
"exclude_iomgrs": [
"uv"
],
- "flaky": false,
+ "flaky": true,
"language": "c",
"name": "h2_proxy_test",
"platforms": [
@@ -17332,6 +17604,30 @@
},
{
"args": [
+ "resource_quota_server"
+ ],
+ "ci_platforms": [
+ "windows",
+ "linux",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [
+ "uv"
+ ],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_sockpair_test",
+ "platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"server_finishes_request"
],
"ci_platforms": [
@@ -19715,7 +20011,7 @@
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [],
- "flaky": false,
+ "flaky": true,
"language": "c",
"name": "h2_ssl_test",
"platforms": [
@@ -20233,6 +20529,29 @@
},
{
"args": [
+ "resource_quota_server"
+ ],
+ "ci_platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_ssl_test",
+ "platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"server_finishes_request"
],
"ci_platforms": [
@@ -20729,7 +21048,7 @@
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [],
- "flaky": false,
+ "flaky": true,
"language": "c",
"name": "h2_ssl_cert_test",
"platforms": [
@@ -21247,6 +21566,29 @@
},
{
"args": [
+ "resource_quota_server"
+ ],
+ "ci_platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_ssl_cert_test",
+ "platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"server_finishes_request"
],
"ci_platforms": [
@@ -21706,7 +22048,7 @@
"exclude_iomgrs": [
"uv"
],
- "flaky": false,
+ "flaky": true,
"language": "c",
"name": "h2_ssl_proxy_test",
"platforms": [
@@ -22631,7 +22973,7 @@
"exclude_iomgrs": [
"uv"
],
- "flaky": false,
+ "flaky": true,
"language": "c",
"name": "h2_uds_test",
"platforms": [
@@ -23148,6 +23490,29 @@
},
{
"args": [
+ "resource_quota_server"
+ ],
+ "ci_platforms": [
+ "linux",
+ "mac",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [
+ "uv"
+ ],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_uds_test",
+ "platforms": [
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"server_finishes_request"
],
"ci_platforms": [
@@ -23621,7 +23986,7 @@
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [],
- "flaky": false,
+ "flaky": true,
"language": "c",
"name": "h2_census_nosec_test",
"platforms": [
@@ -24139,6 +24504,29 @@
},
{
"args": [
+ "resource_quota_server"
+ ],
+ "ci_platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_census_nosec_test",
+ "platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"server_finishes_request"
],
"ci_platforms": [
@@ -24612,7 +25000,7 @@
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [],
- "flaky": false,
+ "flaky": true,
"language": "c",
"name": "h2_compress_nosec_test",
"platforms": [
@@ -25130,6 +25518,29 @@
},
{
"args": [
+ "resource_quota_server"
+ ],
+ "ci_platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_compress_nosec_test",
+ "platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"server_finishes_request"
],
"ci_platforms": [
@@ -25603,7 +26014,7 @@
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [],
- "flaky": false,
+ "flaky": true,
"language": "c",
"name": "h2_fake_resolver_nosec_test",
"platforms": [
@@ -26121,6 +26532,29 @@
},
{
"args": [
+ "resource_quota_server"
+ ],
+ "ci_platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_fake_resolver_nosec_test",
+ "platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"server_finishes_request"
],
"ci_platforms": [
@@ -27018,6 +27452,29 @@
},
{
"args": [
+ "resource_quota_server"
+ ],
+ "ci_platforms": [
+ "linux",
+ "mac",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [
+ "uv"
+ ],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_fd_nosec_test",
+ "platforms": [
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"server_finishes_request"
],
"ci_platforms": [
@@ -27468,7 +27925,7 @@
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [],
- "flaky": false,
+ "flaky": true,
"language": "c",
"name": "h2_full_nosec_test",
"platforms": [
@@ -27986,6 +28443,29 @@
},
{
"args": [
+ "resource_quota_server"
+ ],
+ "ci_platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_full_nosec_test",
+ "platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"server_finishes_request"
],
"ci_platforms": [
@@ -28412,7 +28892,7 @@
"exclude_iomgrs": [
"uv"
],
- "flaky": false,
+ "flaky": true,
"language": "c",
"name": "h2_full+pipe_nosec_test",
"platforms": [
@@ -28839,6 +29319,25 @@
},
{
"args": [
+ "resource_quota_server"
+ ],
+ "ci_platforms": [
+ "linux"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [
+ "uv"
+ ],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_full+pipe_nosec_test",
+ "platforms": [
+ "linux"
+ ]
+ },
+ {
+ "args": [
"server_finishes_request"
],
"ci_platforms": [
@@ -29276,7 +29775,7 @@
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [],
- "flaky": false,
+ "flaky": true,
"language": "c",
"name": "h2_full+trace_nosec_test",
"platforms": [
@@ -29748,6 +30247,29 @@
},
{
"args": [
+ "resource_quota_server"
+ ],
+ "ci_platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_full+trace_nosec_test",
+ "platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"server_finishes_request"
],
"ci_platforms": [
@@ -30231,7 +30753,7 @@
"exclude_iomgrs": [
"uv"
],
- "flaky": false,
+ "flaky": true,
"language": "c",
"name": "h2_http_proxy_nosec_test",
"platforms": [
@@ -30771,6 +31293,30 @@
},
{
"args": [
+ "resource_quota_server"
+ ],
+ "ci_platforms": [
+ "windows",
+ "linux",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [
+ "uv"
+ ],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_http_proxy_nosec_test",
+ "platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"server_finishes_request"
],
"ci_platforms": [
@@ -31253,7 +31799,7 @@
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [],
- "flaky": false,
+ "flaky": true,
"language": "c",
"name": "h2_load_reporting_nosec_test",
"platforms": [
@@ -31771,6 +32317,29 @@
},
{
"args": [
+ "resource_quota_server"
+ ],
+ "ci_platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_load_reporting_nosec_test",
+ "platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"server_finishes_request"
],
"ci_platforms": [
@@ -32206,7 +32775,7 @@
"exclude_iomgrs": [
"uv"
],
- "flaky": false,
+ "flaky": true,
"language": "c",
"name": "h2_proxy_nosec_test",
"platforms": [
@@ -33586,6 +34155,30 @@
},
{
"args": [
+ "resource_quota_server"
+ ],
+ "ci_platforms": [
+ "windows",
+ "linux",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [
+ "uv"
+ ],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_sockpair_nosec_test",
+ "platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"server_finishes_request"
],
"ci_platforms": [
@@ -35872,7 +36465,7 @@
"exclude_iomgrs": [
"uv"
],
- "flaky": false,
+ "flaky": true,
"language": "c",
"name": "h2_uds_nosec_test",
"platforms": [
@@ -36389,6 +36982,29 @@
},
{
"args": [
+ "resource_quota_server"
+ ],
+ "ci_platforms": [
+ "linux",
+ "mac",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [
+ "uv"
+ ],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_uds_nosec_test",
+ "platforms": [
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"server_finishes_request"
],
"ci_platforms": [
@@ -36744,6 +37360,27 @@
{
"args": [
"--scenarios_json",
+ "{\"scenarios\": [{\"name\": \"cpp_protobuf_sync_unary_qps_unconstrained_secure_500kib_resource_quota\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"resource_quota_size\": 512000, \"async_server_threads\": 0, \"core_limit\": 0, \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"server_type\": \"SYNC_SERVER\"}, \"client_config\": {\"client_type\": \"SYNC_CLIENT\", \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 16, \"rpc_type\": \"UNARY\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}, \"num_clients\": 0}]}"
+ ],
+ "boringssl": true,
+ "ci_platforms": [
+ "linux"
+ ],
+ "cpu_cost": 8,
+ "defaults": "boringssl",
+ "exclude_configs": [],
+ "flaky": false,
+ "language": "c++",
+ "name": "json_run_localhost",
+ "platforms": [
+ "linux"
+ ],
+ "shortname": "json_run_localhost:cpp_protobuf_sync_unary_qps_unconstrained_secure_500kib_resource_quota",
+ "timeout_seconds": 180
+ },
+ {
+ "args": [
+ "--scenarios_json",
"{\"scenarios\": [{\"name\": \"cpp_protobuf_async_unary_ping_pong_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 1, \"core_limit\": 1, \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"server_type\": \"ASYNC_SERVER\"}, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 1, \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"UNARY\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}, \"num_clients\": 1}]}"
],
"boringssl": true,
@@ -36786,6 +37423,27 @@
{
"args": [
"--scenarios_json",
+ "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_unary_qps_unconstrained_secure_500kib_resource_quota\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"resource_quota_size\": 512000, \"async_server_threads\": 0, \"core_limit\": 0, \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"server_type\": \"ASYNC_SERVER\"}, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"UNARY\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}, \"num_clients\": 0}]}"
+ ],
+ "boringssl": true,
+ "ci_platforms": [
+ "linux"
+ ],
+ "cpu_cost": 8,
+ "defaults": "boringssl",
+ "exclude_configs": [],
+ "flaky": false,
+ "language": "c++",
+ "name": "json_run_localhost",
+ "platforms": [
+ "linux"
+ ],
+ "shortname": "json_run_localhost:cpp_protobuf_async_unary_qps_unconstrained_secure_500kib_resource_quota",
+ "timeout_seconds": 180
+ },
+ {
+ "args": [
+ "--scenarios_json",
"{\"scenarios\": [{\"name\": \"cpp_protobuf_sync_streaming_ping_pong_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 1, \"core_limit\": 1, \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"server_type\": \"SYNC_SERVER\"}, \"client_config\": {\"client_type\": \"SYNC_CLIENT\", \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 1, \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"STREAMING\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}, \"num_clients\": 1}]}"
],
"boringssl": true,
@@ -36828,6 +37486,27 @@
{
"args": [
"--scenarios_json",
+ "{\"scenarios\": [{\"name\": \"cpp_protobuf_sync_streaming_qps_unconstrained_secure_500kib_resource_quota\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"resource_quota_size\": 512000, \"async_server_threads\": 0, \"core_limit\": 0, \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"server_type\": \"SYNC_SERVER\"}, \"client_config\": {\"client_type\": \"SYNC_CLIENT\", \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 16, \"rpc_type\": \"STREAMING\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}, \"num_clients\": 0}]}"
+ ],
+ "boringssl": true,
+ "ci_platforms": [
+ "linux"
+ ],
+ "cpu_cost": 8,
+ "defaults": "boringssl",
+ "exclude_configs": [],
+ "flaky": false,
+ "language": "c++",
+ "name": "json_run_localhost",
+ "platforms": [
+ "linux"
+ ],
+ "shortname": "json_run_localhost:cpp_protobuf_sync_streaming_qps_unconstrained_secure_500kib_resource_quota",
+ "timeout_seconds": 180
+ },
+ {
+ "args": [
+ "--scenarios_json",
"{\"scenarios\": [{\"name\": \"cpp_protobuf_async_streaming_ping_pong_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 1, \"core_limit\": 1, \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"server_type\": \"ASYNC_SERVER\"}, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 1, \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"STREAMING\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}, \"num_clients\": 1}]}"
],
"boringssl": true,
@@ -36870,6 +37549,27 @@
{
"args": [
"--scenarios_json",
+ "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_streaming_qps_unconstrained_secure_500kib_resource_quota\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"resource_quota_size\": 512000, \"async_server_threads\": 0, \"core_limit\": 0, \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"server_type\": \"ASYNC_SERVER\"}, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"STREAMING\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}, \"num_clients\": 0}]}"
+ ],
+ "boringssl": true,
+ "ci_platforms": [
+ "linux"
+ ],
+ "cpu_cost": 8,
+ "defaults": "boringssl",
+ "exclude_configs": [],
+ "flaky": false,
+ "language": "c++",
+ "name": "json_run_localhost",
+ "platforms": [
+ "linux"
+ ],
+ "shortname": "json_run_localhost:cpp_protobuf_async_streaming_qps_unconstrained_secure_500kib_resource_quota",
+ "timeout_seconds": 180
+ },
+ {
+ "args": [
+ "--scenarios_json",
"{\"scenarios\": [{\"name\": \"cpp_generic_async_streaming_ping_pong_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 1, \"core_limit\": 1, \"security_params\": null, \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"server_type\": \"ASYNC_GENERIC_SERVER\"}, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": null, \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 1, \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"STREAMING\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}, \"num_clients\": 1}]}"
],
"boringssl": true,
@@ -37017,6 +37717,27 @@
{
"args": [
"--scenarios_json",
+ "{\"scenarios\": [{\"name\": \"cpp_protobuf_sync_unary_qps_unconstrained_insecure_500kib_resource_quota\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"resource_quota_size\": 512000, \"async_server_threads\": 0, \"core_limit\": 0, \"security_params\": null, \"server_type\": \"SYNC_SERVER\"}, \"client_config\": {\"client_type\": \"SYNC_CLIENT\", \"security_params\": null, \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 16, \"rpc_type\": \"UNARY\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}, \"num_clients\": 0}]}"
+ ],
+ "boringssl": true,
+ "ci_platforms": [
+ "linux"
+ ],
+ "cpu_cost": 8,
+ "defaults": "boringssl",
+ "exclude_configs": [],
+ "flaky": false,
+ "language": "c++",
+ "name": "json_run_localhost",
+ "platforms": [
+ "linux"
+ ],
+ "shortname": "json_run_localhost:cpp_protobuf_sync_unary_qps_unconstrained_insecure_500kib_resource_quota",
+ "timeout_seconds": 180
+ },
+ {
+ "args": [
+ "--scenarios_json",
"{\"scenarios\": [{\"name\": \"cpp_protobuf_async_unary_ping_pong_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 1, \"core_limit\": 1, \"security_params\": null, \"server_type\": \"ASYNC_SERVER\"}, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": null, \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 1, \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"UNARY\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}, \"num_clients\": 1}]}"
],
"boringssl": true,
@@ -37059,6 +37780,27 @@
{
"args": [
"--scenarios_json",
+ "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_unary_qps_unconstrained_insecure_500kib_resource_quota\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"resource_quota_size\": 512000, \"async_server_threads\": 0, \"core_limit\": 0, \"security_params\": null, \"server_type\": \"ASYNC_SERVER\"}, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": null, \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"UNARY\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}, \"num_clients\": 0}]}"
+ ],
+ "boringssl": true,
+ "ci_platforms": [
+ "linux"
+ ],
+ "cpu_cost": 8,
+ "defaults": "boringssl",
+ "exclude_configs": [],
+ "flaky": false,
+ "language": "c++",
+ "name": "json_run_localhost",
+ "platforms": [
+ "linux"
+ ],
+ "shortname": "json_run_localhost:cpp_protobuf_async_unary_qps_unconstrained_insecure_500kib_resource_quota",
+ "timeout_seconds": 180
+ },
+ {
+ "args": [
+ "--scenarios_json",
"{\"scenarios\": [{\"name\": \"cpp_protobuf_sync_streaming_ping_pong_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 1, \"core_limit\": 1, \"security_params\": null, \"server_type\": \"SYNC_SERVER\"}, \"client_config\": {\"client_type\": \"SYNC_CLIENT\", \"security_params\": null, \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 1, \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"STREAMING\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}, \"num_clients\": 1}]}"
],
"boringssl": true,
@@ -37101,6 +37843,27 @@
{
"args": [
"--scenarios_json",
+ "{\"scenarios\": [{\"name\": \"cpp_protobuf_sync_streaming_qps_unconstrained_insecure_500kib_resource_quota\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"resource_quota_size\": 512000, \"async_server_threads\": 0, \"core_limit\": 0, \"security_params\": null, \"server_type\": \"SYNC_SERVER\"}, \"client_config\": {\"client_type\": \"SYNC_CLIENT\", \"security_params\": null, \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 16, \"rpc_type\": \"STREAMING\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}, \"num_clients\": 0}]}"
+ ],
+ "boringssl": true,
+ "ci_platforms": [
+ "linux"
+ ],
+ "cpu_cost": 8,
+ "defaults": "boringssl",
+ "exclude_configs": [],
+ "flaky": false,
+ "language": "c++",
+ "name": "json_run_localhost",
+ "platforms": [
+ "linux"
+ ],
+ "shortname": "json_run_localhost:cpp_protobuf_sync_streaming_qps_unconstrained_insecure_500kib_resource_quota",
+ "timeout_seconds": 180
+ },
+ {
+ "args": [
+ "--scenarios_json",
"{\"scenarios\": [{\"name\": \"cpp_protobuf_async_streaming_ping_pong_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 1, \"core_limit\": 1, \"security_params\": null, \"server_type\": \"ASYNC_SERVER\"}, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": null, \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 1, \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"STREAMING\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}, \"num_clients\": 1}]}"
],
"boringssl": true,
@@ -37142,6 +37905,27 @@
},
{
"args": [
+ "--scenarios_json",
+ "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_streaming_qps_unconstrained_insecure_500kib_resource_quota\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"resource_quota_size\": 512000, \"async_server_threads\": 0, \"core_limit\": 0, \"security_params\": null, \"server_type\": \"ASYNC_SERVER\"}, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": null, \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"STREAMING\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}, \"num_clients\": 0}]}"
+ ],
+ "boringssl": true,
+ "ci_platforms": [
+ "linux"
+ ],
+ "cpu_cost": 8,
+ "defaults": "boringssl",
+ "exclude_configs": [],
+ "flaky": false,
+ "language": "c++",
+ "name": "json_run_localhost",
+ "platforms": [
+ "linux"
+ ],
+ "shortname": "json_run_localhost:cpp_protobuf_async_streaming_qps_unconstrained_insecure_500kib_resource_quota",
+ "timeout_seconds": 180
+ },
+ {
+ "args": [
"test/core/end2end/fuzzers/api_fuzzer_corpus/00.bin"
],
"ci_platforms": [
diff --git a/vsprojects/buildtests_c.sln b/vsprojects/buildtests_c.sln
index 339b42f9d7..b1918809bf 100644
--- a/vsprojects/buildtests_c.sln
+++ b/vsprojects/buildtests_c.sln
@@ -1317,6 +1317,17 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "resolve_address_test", "vcx
{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
EndProjectSection
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "resource_quota_test", "vcxproj\test\resource_quota_test\resource_quota_test.vcxproj", "{6084F546-5D66-5CB5-63CF-DC960F14B545}"
+ ProjectSection(myProperties) = preProject
+ lib = "False"
+ EndProjectSection
+ ProjectSection(ProjectDependencies) = postProject
+ {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} = {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}
+ {29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9}
+ {EAB0A629-17A9-44DB-B5FF-E91A721FE037} = {EAB0A629-17A9-44DB-B5FF-E91A721FE037}
+ {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
+ EndProjectSection
+EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "secure_channel_create_test", "vcxproj\test\secure_channel_create_test\secure_channel_create_test.vcxproj", "{62B25398-7173-928E-689E-53860B0ACFC4}"
ProjectSection(myProperties) = preProject
lib = "False"
@@ -3538,6 +3549,22 @@ Global
{8279AF6C-9584-67F3-1547-B204864FCCA7}.Release-DLL|Win32.Build.0 = Release|Win32
{8279AF6C-9584-67F3-1547-B204864FCCA7}.Release-DLL|x64.ActiveCfg = Release|x64
{8279AF6C-9584-67F3-1547-B204864FCCA7}.Release-DLL|x64.Build.0 = Release|x64
+ {6084F546-5D66-5CB5-63CF-DC960F14B545}.Debug|Win32.ActiveCfg = Debug|Win32
+ {6084F546-5D66-5CB5-63CF-DC960F14B545}.Debug|x64.ActiveCfg = Debug|x64
+ {6084F546-5D66-5CB5-63CF-DC960F14B545}.Release|Win32.ActiveCfg = Release|Win32
+ {6084F546-5D66-5CB5-63CF-DC960F14B545}.Release|x64.ActiveCfg = Release|x64
+ {6084F546-5D66-5CB5-63CF-DC960F14B545}.Debug|Win32.Build.0 = Debug|Win32
+ {6084F546-5D66-5CB5-63CF-DC960F14B545}.Debug|x64.Build.0 = Debug|x64
+ {6084F546-5D66-5CB5-63CF-DC960F14B545}.Release|Win32.Build.0 = Release|Win32
+ {6084F546-5D66-5CB5-63CF-DC960F14B545}.Release|x64.Build.0 = Release|x64
+ {6084F546-5D66-5CB5-63CF-DC960F14B545}.Debug-DLL|Win32.ActiveCfg = Debug|Win32
+ {6084F546-5D66-5CB5-63CF-DC960F14B545}.Debug-DLL|Win32.Build.0 = Debug|Win32
+ {6084F546-5D66-5CB5-63CF-DC960F14B545}.Debug-DLL|x64.ActiveCfg = Debug|x64
+ {6084F546-5D66-5CB5-63CF-DC960F14B545}.Debug-DLL|x64.Build.0 = Debug|x64
+ {6084F546-5D66-5CB5-63CF-DC960F14B545}.Release-DLL|Win32.ActiveCfg = Release|Win32
+ {6084F546-5D66-5CB5-63CF-DC960F14B545}.Release-DLL|Win32.Build.0 = Release|Win32
+ {6084F546-5D66-5CB5-63CF-DC960F14B545}.Release-DLL|x64.ActiveCfg = Release|x64
+ {6084F546-5D66-5CB5-63CF-DC960F14B545}.Release-DLL|x64.Build.0 = Release|x64
{62B25398-7173-928E-689E-53860B0ACFC4}.Debug|Win32.ActiveCfg = Debug|Win32
{62B25398-7173-928E-689E-53860B0ACFC4}.Debug|x64.ActiveCfg = Debug|x64
{62B25398-7173-928E-689E-53860B0ACFC4}.Release|Win32.ActiveCfg = Release|Win32
diff --git a/vsprojects/vcxproj/grpc++/grpc++.vcxproj b/vsprojects/vcxproj/grpc++/grpc++.vcxproj
index 6bb9a6169d..43c5281a02 100644
--- a/vsprojects/vcxproj/grpc++/grpc++.vcxproj
+++ b/vsprojects/vcxproj/grpc++/grpc++.vcxproj
@@ -285,6 +285,7 @@
<ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\thd.h" />
<ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\thd_cxx11.h" />
<ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\thd_no_cxx11.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc++\resource_quota.h" />
<ClInclude Include="$(SolutionDir)\..\include\grpc++\security\auth_context.h" />
<ClInclude Include="$(SolutionDir)\..\include\grpc++\security\auth_metadata_processor.h" />
<ClInclude Include="$(SolutionDir)\..\include\grpc++\security\credentials.h" />
@@ -403,6 +404,8 @@
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\cpp\common\core_codegen.cc">
</ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\cpp\common\resource_quota_cc.cc">
+ </ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\cpp\common\rpc_method.cc">
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\cpp\server\async_generic_service.cc">
diff --git a/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters b/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters
index 761424c3fa..6ad212a125 100644
--- a/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters
@@ -58,6 +58,9 @@
<ClCompile Include="$(SolutionDir)\..\src\cpp\common\core_codegen.cc">
<Filter>src\cpp\common</Filter>
</ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\cpp\common\resource_quota_cc.cc">
+ <Filter>src\cpp\common</Filter>
+ </ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\cpp\common\rpc_method.cc">
<Filter>src\cpp\common</Filter>
</ClCompile>
@@ -186,6 +189,9 @@
<ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\thd_no_cxx11.h">
<Filter>include\grpc++\impl</Filter>
</ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc++\resource_quota.h">
+ <Filter>include\grpc++</Filter>
+ </ClInclude>
<ClInclude Include="$(SolutionDir)\..\include\grpc++\security\auth_context.h">
<Filter>include\grpc++\security</Filter>
</ClInclude>
diff --git a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj
index 02e65926fe..9e6f2c0d0f 100644
--- a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj
+++ b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj
@@ -285,6 +285,7 @@
<ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\thd.h" />
<ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\thd_cxx11.h" />
<ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\thd_no_cxx11.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc++\resource_quota.h" />
<ClInclude Include="$(SolutionDir)\..\include\grpc++\security\auth_context.h" />
<ClInclude Include="$(SolutionDir)\..\include\grpc++\security\auth_metadata_processor.h" />
<ClInclude Include="$(SolutionDir)\..\include\grpc++\security\credentials.h" />
@@ -389,6 +390,8 @@
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\cpp\common\core_codegen.cc">
</ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\cpp\common\resource_quota_cc.cc">
+ </ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\cpp\common\rpc_method.cc">
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\cpp\server\async_generic_service.cc">
diff --git a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters
index ff1a0e9644..c73be4e63f 100644
--- a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters
@@ -43,6 +43,9 @@
<ClCompile Include="$(SolutionDir)\..\src\cpp\common\core_codegen.cc">
<Filter>src\cpp\common</Filter>
</ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\cpp\common\resource_quota_cc.cc">
+ <Filter>src\cpp\common</Filter>
+ </ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\cpp\common\rpc_method.cc">
<Filter>src\cpp\common</Filter>
</ClCompile>
@@ -171,6 +174,9 @@
<ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\thd_no_cxx11.h">
<Filter>include\grpc++\impl</Filter>
</ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc++\resource_quota.h">
+ <Filter>include\grpc++</Filter>
+ </ClInclude>
<ClInclude Include="$(SolutionDir)\..\include\grpc++\security\auth_context.h">
<Filter>include\grpc++\security</Filter>
</ClInclude>
diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj b/vsprojects/vcxproj/grpc/grpc.vcxproj
index b9d97fec6c..d9d0d42d67 100644
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj
+++ b/vsprojects/vcxproj/grpc/grpc.vcxproj
@@ -337,6 +337,7 @@
<ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_windows.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\port.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\resource_quota.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_posix.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_utils.h" />
@@ -345,6 +346,7 @@
<ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_posix.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_windows.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_posix.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_posix.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_uv.h" />
@@ -559,6 +561,8 @@
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address_windows.c">
</ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resource_quota.c">
+ </ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_utils.c">
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_common_posix.c">
diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
index 86f7edae29..ab9b76073c 100644
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
@@ -136,6 +136,9 @@
<ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address_windows.c">
<Filter>src\core\lib\iomgr</Filter>
</ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resource_quota.c">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_utils.c">
<Filter>src\core\lib\iomgr</Filter>
</ClCompile>
@@ -830,6 +833,9 @@
<ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address.h">
<Filter>src\core\lib\iomgr</Filter>
</ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\resource_quota.h">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClInclude>
<ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr.h">
<Filter>src\core\lib\iomgr</Filter>
</ClInclude>
@@ -854,6 +860,9 @@
<ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client.h">
<Filter>src\core\lib\iomgr</Filter>
</ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_posix.h">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClInclude>
<ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_posix.h">
<Filter>src\core\lib\iomgr</Filter>
</ClInclude>
diff --git a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
index 35ace6eabb..39c144d992 100644
--- a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
+++ b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
@@ -230,6 +230,7 @@
<ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_windows.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\port.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\resource_quota.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_posix.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_utils.h" />
@@ -238,6 +239,7 @@
<ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_posix.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_windows.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_posix.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_posix.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_uv.h" />
@@ -410,6 +412,8 @@
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address_windows.c">
</ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resource_quota.c">
+ </ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_utils.c">
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_common_posix.c">
diff --git a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters
index 4b104aeb9b..0fbfc3acd3 100644
--- a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters
@@ -193,6 +193,9 @@
<ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address_windows.c">
<Filter>src\core\lib\iomgr</Filter>
</ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resource_quota.c">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_utils.c">
<Filter>src\core\lib\iomgr</Filter>
</ClCompile>
@@ -626,6 +629,9 @@
<ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address.h">
<Filter>src\core\lib\iomgr</Filter>
</ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\resource_quota.h">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClInclude>
<ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr.h">
<Filter>src\core\lib\iomgr</Filter>
</ClInclude>
@@ -650,6 +656,9 @@
<ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client.h">
<Filter>src\core\lib\iomgr</Filter>
</ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_posix.h">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClInclude>
<ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_posix.h">
<Filter>src\core\lib\iomgr</Filter>
</ClInclude>
diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
index 377bbf9bbd..87e3921ff9 100644
--- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
+++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
@@ -327,6 +327,7 @@
<ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_windows.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\port.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\resource_quota.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_posix.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_utils.h" />
@@ -335,6 +336,7 @@
<ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_posix.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_windows.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_posix.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_posix.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_uv.h" />
@@ -527,6 +529,8 @@
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address_windows.c">
</ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resource_quota.c">
+ </ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_utils.c">
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_common_posix.c">
diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
index 9171f82377..1e719226fa 100644
--- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
@@ -139,6 +139,9 @@
<ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address_windows.c">
<Filter>src\core\lib\iomgr</Filter>
</ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resource_quota.c">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_utils.c">
<Filter>src\core\lib\iomgr</Filter>
</ClCompile>
@@ -743,6 +746,9 @@
<ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address.h">
<Filter>src\core\lib\iomgr</Filter>
</ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\resource_quota.h">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClInclude>
<ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr.h">
<Filter>src\core\lib\iomgr</Filter>
</ClInclude>
@@ -767,6 +773,9 @@
<ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client.h">
<Filter>src\core\lib\iomgr</Filter>
</ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_posix.h">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClInclude>
<ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_posix.h">
<Filter>src\core\lib\iomgr</Filter>
</ClInclude>
diff --git a/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj b/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj
index d6ec36962f..a47c40f0f7 100644
--- a/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj
+++ b/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj
@@ -221,6 +221,8 @@
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\request_with_payload.c">
</ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\resource_quota_server.c">
+ </ClCompile>
<ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\server_finishes_request.c">
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\shutdown_finishes_calls.c">
diff --git a/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj.filters b/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj.filters
index a6c24a895a..71cf6838fe 100644
--- a/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj.filters
+++ b/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj.filters
@@ -106,6 +106,9 @@
<ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\request_with_payload.c">
<Filter>test\core\end2end\tests</Filter>
</ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\resource_quota_server.c">
+ <Filter>test\core\end2end\tests</Filter>
+ </ClCompile>
<ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\server_finishes_request.c">
<Filter>test\core\end2end\tests</Filter>
</ClCompile>
diff --git a/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj b/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj
index 085b14700c..68ff5f1ebd 100644
--- a/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj
+++ b/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj
@@ -223,6 +223,8 @@
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\request_with_payload.c">
</ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\resource_quota_server.c">
+ </ClCompile>
<ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\server_finishes_request.c">
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\shutdown_finishes_calls.c">
diff --git a/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj.filters b/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj.filters
index d224a9ced9..7a620f61a5 100644
--- a/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj.filters
+++ b/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj.filters
@@ -109,6 +109,9 @@
<ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\request_with_payload.c">
<Filter>test\core\end2end\tests</Filter>
</ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\resource_quota_server.c">
+ <Filter>test\core\end2end\tests</Filter>
+ </ClCompile>
<ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\server_finishes_request.c">
<Filter>test\core\end2end\tests</Filter>
</ClCompile>
diff --git a/vsprojects/vcxproj/test/resource_quota_test/resource_quota_test.vcxproj b/vsprojects/vcxproj/test/resource_quota_test/resource_quota_test.vcxproj
new file mode 100644
index 0000000000..389340e9a0
--- /dev/null
+++ b/vsprojects/vcxproj/test/resource_quota_test/resource_quota_test.vcxproj
@@ -0,0 +1,199 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\1.0.204.1.props')" />
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{6084F546-5D66-5CB5-63CF-DC960F14B545}</ProjectGuid>
+ <IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected>
+ <IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(VisualStudioVersion)' == '10.0'" Label="Configuration">
+ <PlatformToolset>v100</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(VisualStudioVersion)' == '11.0'" Label="Configuration">
+ <PlatformToolset>v110</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(VisualStudioVersion)' == '12.0'" Label="Configuration">
+ <PlatformToolset>v120</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(VisualStudioVersion)' == '14.0'" Label="Configuration">
+ <PlatformToolset>v140</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(SolutionDir)\..\vsprojects\global.props" />
+ <Import Project="$(SolutionDir)\..\vsprojects\openssl.props" />
+ <Import Project="$(SolutionDir)\..\vsprojects\winsock.props" />
+ <Import Project="$(SolutionDir)\..\vsprojects\zlib.props" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)'=='Debug'">
+ <TargetName>resource_quota_test</TargetName>
+ <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+ <Configuration-grpc_dependencies_zlib>Debug</Configuration-grpc_dependencies_zlib>
+ <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
+ <Configuration-grpc_dependencies_openssl>Debug</Configuration-grpc_dependencies_openssl>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)'=='Release'">
+ <TargetName>resource_quota_test</TargetName>
+ <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+ <Configuration-grpc_dependencies_zlib>Release</Configuration-grpc_dependencies_zlib>
+ <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
+ <Configuration-grpc_dependencies_openssl>Release</Configuration-grpc_dependencies_openssl>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <SDLCheck>true</SDLCheck>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+ <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+ <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <SDLCheck>true</SDLCheck>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+ <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+ <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>MaxSpeed</Optimization>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <SDLCheck>true</SDLCheck>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+ <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+ <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ </Link>
+ </ItemDefinitionGroup>
+
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>MaxSpeed</Optimization>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <SDLCheck>true</SDLCheck>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+ <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+ <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ </Link>
+ </ItemDefinitionGroup>
+
+ <ItemGroup>
+ <ClCompile Include="$(SolutionDir)\..\test\core\iomgr\resource_quota_test.c">
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_test_util\grpc_test_util.vcxproj">
+ <Project>{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}</Project>
+ </ProjectReference>
+ <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc\grpc.vcxproj">
+ <Project>{29D16885-7228-4C31-81ED-5F9187C7F2A9}</Project>
+ </ProjectReference>
+ <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr_test_util\gpr_test_util.vcxproj">
+ <Project>{EAB0A629-17A9-44DB-B5FF-E91A721FE037}</Project>
+ </ProjectReference>
+ <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr\gpr.vcxproj">
+ <Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</Project>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="packages.config" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+ <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+ <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+ <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+ </ImportGroup>
+ <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+ <PropertyGroup>
+ <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+ </PropertyGroup>
+ <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" />
+ <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" />
+ <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" />
+ <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" />
+ <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" />
+ </Target>
+</Project>
+
diff --git a/vsprojects/vcxproj/test/resource_quota_test/resource_quota_test.vcxproj.filters b/vsprojects/vcxproj/test/resource_quota_test/resource_quota_test.vcxproj.filters
new file mode 100644
index 0000000000..d76c8aed5d
--- /dev/null
+++ b/vsprojects/vcxproj/test/resource_quota_test/resource_quota_test.vcxproj.filters
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <ClCompile Include="$(SolutionDir)\..\test\core\iomgr\resource_quota_test.c">
+ <Filter>test\core\iomgr</Filter>
+ </ClCompile>
+ </ItemGroup>
+
+ <ItemGroup>
+ <Filter Include="test">
+ <UniqueIdentifier>{06783e32-dbf0-7e7c-7b50-12b278f9cc12}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="test\core">
+ <UniqueIdentifier>{c4f432b6-577b-e3ed-fec9-a915af5ebbd5}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="test\core\iomgr">
+ <UniqueIdentifier>{fcc82d68-ffb2-0843-83aa-175006c43aeb}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+</Project>
+