aboutsummaryrefslogtreecommitdiffhomepage
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-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.c363
-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
39 files changed, 1483 insertions, 91 deletions
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..fbd4986dfb
--- /dev/null
+++ b/test/core/end2end/tests/resource_quota_server.c
@@ -0,0 +1,363 @@
+/*
+ *
+ * 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;
+ const size_t output_size = 1024 * 1024;
+ output = gpr_malloc(output_size);
+ for (i = 0; i < output_size - 1; ++i) {
+ output[i] = chars[rand() % (int)(sizeof(chars) - 1)];
+ }
+ output[output_size - 1] = '\0';
+ gpr_slice out = gpr_slice_from_copied_string(output);
+ gpr_free(output);
+ return out;
+}
+
+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 519a1fe3e0..cf3372c3cf 100644
--- a/test/cpp/qps/driver.cc
+++ b/test/cpp/qps/driver.cc
@@ -134,7 +134,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);
@@ -172,6 +173,23 @@ static void postprocess_scenario_result(ScenarioResult* result) {
average(result->server_stats(), ServerTotalCpuTime);
result->mutable_summary()->set_server_cpu_usage(server_cpu_usage);
}
+
+ 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
@@ -459,6 +477,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++) {
@@ -477,6 +496,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));
@@ -496,6 +519,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 a06d962bf2..7f84816421 100644
--- a/test/cpp/qps/report.cc
+++ b/test/cpp/qps/report.cc
@@ -79,6 +79,12 @@ void CompositeReporter::ReportCpuUsage(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();