From ef9ccd167c1cae38a172698109075a89af61f36c Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 22 Feb 2017 16:17:46 -0800 Subject: [PATCH 001/127] Check max streams --- src/core/ext/transport/chttp2/transport/parsing.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/core/ext/transport/chttp2/transport/parsing.c b/src/core/ext/transport/chttp2/transport/parsing.c index 7ed00522c3e..035c4ef28d0 100644 --- a/src/core/ext/transport/chttp2/transport/parsing.c +++ b/src/core/ext/transport/chttp2/transport/parsing.c @@ -634,6 +634,10 @@ static grpc_error *init_header_frame_parser(grpc_exec_ctx *exec_ctx, "ignoring grpc_chttp2_stream with non-client generated index %d", t->incoming_stream_id)); return init_skip_frame_parser(exec_ctx, t, 1); + } else if (grpc_chttp2_stream_map_size(&t->stream_map) >= + t->settings[GRPC_ACKED_SETTINGS] + [GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS]) { + return GRPC_ERROR_CREATE("Max stream count exceeded"); } t->last_new_stream_id = t->incoming_stream_id; s = t->incoming_stream = From bb742675a80925f4701a3ecce99d3b104e23c9a1 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 17 May 2017 22:19:05 +0000 Subject: [PATCH 002/127] Enable epoll1 poller --- src/core/lib/iomgr/ev_epoll1_linux.c | 5 +---- src/core/lib/iomgr/ev_epollsig_linux.c | 2 +- tools/run_tests/run_tests.py | 4 ++-- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/core/lib/iomgr/ev_epoll1_linux.c b/src/core/lib/iomgr/ev_epoll1_linux.c index ad69f808cdb..0f067b52a3a 100644 --- a/src/core/lib/iomgr/ev_epoll1_linux.c +++ b/src/core/lib/iomgr/ev_epoll1_linux.c @@ -668,9 +668,9 @@ static void end_worker(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, } } else { gpr_atm_no_barrier_store(&g_active_poller, 0); - gpr_mu_unlock(&pollset->mu); size_t poller_neighbourhood_idx = (size_t)(pollset->neighbourhood - g_neighbourhoods); + gpr_mu_unlock(&pollset->mu); bool found_worker = false; bool scan_state[MAX_NEIGHBOURHOODS]; for (size_t i = 0; !found_worker && i < g_num_neighbourhoods; i++) { @@ -948,9 +948,6 @@ static const grpc_event_engine_vtable vtable = { /* It is possible that GLIBC has epoll but the underlying kernel doesn't. * Create a dummy epoll_fd to make sure epoll support is available */ const grpc_event_engine_vtable *grpc_init_epoll1_linux(bool explicit_request) { - /* TODO(ctiller): temporary, until this stabilizes */ - if (!explicit_request) return NULL; - if (!grpc_has_wakeup_fd()) { return NULL; } diff --git a/src/core/lib/iomgr/ev_epollsig_linux.c b/src/core/lib/iomgr/ev_epollsig_linux.c index 92c555b7eae..25a4d32cfc5 100644 --- a/src/core/lib/iomgr/ev_epollsig_linux.c +++ b/src/core/lib/iomgr/ev_epollsig_linux.c @@ -1937,7 +1937,7 @@ const grpc_event_engine_vtable *grpc_init_epollsig_linux( if (!is_grpc_wakeup_signal_initialized) { /* TODO(ctiller): when other epoll engines are ready, remove the true || to * force this to be explitly chosen if needed */ - if (true || explicit_request) { + if (explicit_request) { grpc_use_signal(SIGRTMIN + 6); } else { return NULL; diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py index 1a16b093259..d1a9e73aa13 100755 --- a/tools/run_tests/run_tests.py +++ b/tools/run_tests/run_tests.py @@ -75,8 +75,8 @@ _FORCE_ENVIRON_FOR_WRAPPERS = { _POLLING_STRATEGIES = { - 'linux': ['epollsig', 'poll', 'poll-cv'], -# TODO(ctiller, sreecha): enable epoll1, epollex, epoll-thread-pool + 'linux': ['epoll1', 'epollsig', 'poll', 'poll-cv'], +# TODO(ctiller, sreecha): enable epollex, epoll-thread-pool 'mac': ['poll'], } From 2b73c4434f92e0efd8722da722124950338f84f5 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Thu, 18 May 2017 16:25:34 -0700 Subject: [PATCH 003/127] Extend test timeout --- build.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/build.yaml b/build.yaml index ecd9ebe5b7b..98f0dd739d9 100644 --- a/build.yaml +++ b/build.yaml @@ -4389,6 +4389,7 @@ targets: cpu_cost: 100 build: test language: c++ + timeout_seconds: 1200 src: - test/cpp/end2end/thread_stress_test.cc deps: From 058bd64b00ea7bdceaa83063466a83a1c4fac8c3 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Thu, 18 May 2017 16:26:15 -0700 Subject: [PATCH 004/127] Generate projects --- build.yaml | 2 +- tools/run_tests/generated/tests.json | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/build.yaml b/build.yaml index 98f0dd739d9..14cbe954691 100644 --- a/build.yaml +++ b/build.yaml @@ -4389,7 +4389,6 @@ targets: cpu_cost: 100 build: test language: c++ - timeout_seconds: 1200 src: - test/cpp/end2end/thread_stress_test.cc deps: @@ -4399,6 +4398,7 @@ targets: - grpc - gpr_test_util - gpr + timeout_seconds: 1200 - name: writes_per_rpc_test gtest: true cpu_cost: 0.5 diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json index d1e3a99a084..f91913c69f6 100644 --- a/tools/run_tests/generated/tests.json +++ b/tools/run_tests/generated/tests.json @@ -3889,7 +3889,8 @@ "mac", "posix", "windows" - ] + ], + "timeout_seconds": 1200 }, { "args": [], From 55624a3a99f47a528b19c40f16901f560ccd51a5 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 26 May 2017 08:14:44 -0700 Subject: [PATCH 005/127] Fix some kicking bugs --- src/core/lib/iomgr/ev_epoll1_linux.c | 74 +++++++++++++++++++--------- 1 file changed, 52 insertions(+), 22 deletions(-) diff --git a/src/core/lib/iomgr/ev_epoll1_linux.c b/src/core/lib/iomgr/ev_epoll1_linux.c index 0f067b52a3a..64eef092fab 100644 --- a/src/core/lib/iomgr/ev_epoll1_linux.c +++ b/src/core/lib/iomgr/ev_epoll1_linux.c @@ -95,6 +95,7 @@ typedef enum { UNKICKED, KICKED, DESIGNATED_POLLER } kick_state; struct grpc_pollset_worker { kick_state kick_state; + int kick_state_mutator; // which line of code last changed kick state bool initialized_cv; grpc_pollset_worker *next; grpc_pollset_worker *prev; @@ -102,6 +103,12 @@ struct grpc_pollset_worker { grpc_closure_list schedule_on_end_work; }; +#define SET_KICK_STATE(worker, state) \ + do { \ + (worker)->kick_state = (state); \ + (worker)->kick_state_mutator = __LINE__; \ + } while (false) + #define MAX_NEIGHBOURHOODS 1024 typedef struct pollset_neighbourhood { @@ -431,13 +438,20 @@ static grpc_error *pollset_kick_all(grpc_pollset *pollset) { if (pollset->root_worker != NULL) { grpc_pollset_worker *worker = pollset->root_worker; do { - if (worker->initialized_cv) { - worker->kick_state = KICKED; - gpr_cv_signal(&worker->cv); - } else { - worker->kick_state = KICKED; - append_error(&error, grpc_wakeup_fd_wakeup(&global_wakeup_fd), - "pollset_shutdown"); + switch (worker->kick_state) { + case KICKED: + break; + case UNKICKED: + SET_KICK_STATE(worker, KICKED); + if (worker->initialized_cv) { + gpr_cv_signal(&worker->cv); + } + break; + case DESIGNATED_POLLER: + SET_KICK_STATE(worker, KICKED); + append_error(&error, grpc_wakeup_fd_wakeup(&global_wakeup_fd), + "pollset_shutdown"); + break; } worker = worker->next; @@ -534,7 +548,7 @@ static bool begin_worker(grpc_pollset *pollset, grpc_pollset_worker *worker, gpr_timespec deadline) { if (worker_hdl != NULL) *worker_hdl = worker; worker->initialized_cv = false; - worker->kick_state = UNKICKED; + SET_KICK_STATE(worker, UNKICKED); worker->schedule_on_end_work = (grpc_closure_list)GRPC_CLOSURE_LIST_INIT; pollset->begin_refs++; @@ -563,8 +577,9 @@ static bool begin_worker(grpc_pollset *pollset, grpc_pollset_worker *worker, pollset->seen_inactive = false; if (neighbourhood->active_root == NULL) { neighbourhood->active_root = pollset->next = pollset->prev = pollset; - if (gpr_atm_no_barrier_cas(&g_active_poller, 0, (gpr_atm)worker)) { - worker->kick_state = DESIGNATED_POLLER; + if (worker->kick_state == UNKICKED && + gpr_atm_no_barrier_cas(&g_active_poller, 0, (gpr_atm)worker)) { + SET_KICK_STATE(worker, DESIGNATED_POLLER); } } else { pollset->next = neighbourhood->active_root; @@ -588,7 +603,7 @@ static bool begin_worker(grpc_pollset *pollset, grpc_pollset_worker *worker, pollset->shutdown_closure == NULL) { if (gpr_cv_wait(&worker->cv, &pollset->mu, deadline) && worker->kick_state == UNKICKED) { - worker->kick_state = KICKED; + SET_KICK_STATE(worker, KICKED); } } *now = gpr_now(now->clock_type); @@ -615,7 +630,7 @@ static bool check_neighbourhood_for_available_poller( case UNKICKED: if (gpr_atm_no_barrier_cas(&g_active_poller, 0, (gpr_atm)inspect_worker)) { - inspect_worker->kick_state = DESIGNATED_POLLER; + SET_KICK_STATE(inspect_worker, DESIGNATED_POLLER); if (inspect_worker->initialized_cv) { gpr_cv_signal(&inspect_worker->cv); } @@ -652,14 +667,14 @@ static void end_worker(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_pollset_worker *worker, grpc_pollset_worker **worker_hdl) { if (worker_hdl != NULL) *worker_hdl = NULL; - worker->kick_state = KICKED; + SET_KICK_STATE(worker, KICKED); grpc_closure_list_move(&worker->schedule_on_end_work, &exec_ctx->closure_list); if (gpr_atm_no_barrier_load(&g_active_poller) == (gpr_atm)worker) { if (worker->next != worker && worker->next->kick_state == UNKICKED) { GPR_ASSERT(worker->next->initialized_cv); gpr_atm_no_barrier_store(&g_active_poller, (gpr_atm)worker->next); - worker->next->kick_state = DESIGNATED_POLLER; + SET_KICK_STATE(worker->next, DESIGNATED_POLLER); gpr_cv_signal(&worker->next->cv); if (grpc_exec_ctx_has_work(exec_ctx)) { gpr_mu_unlock(&pollset->mu); @@ -752,38 +767,53 @@ static grpc_error *pollset_kick(grpc_pollset *pollset, return GRPC_ERROR_NONE; } grpc_pollset_worker *next_worker = root_worker->next; - if (root_worker == next_worker && + if (root_worker == next_worker && // only try and wake up a poller if + // there is no next worker root_worker == (grpc_pollset_worker *)gpr_atm_no_barrier_load( &g_active_poller)) { - root_worker->kick_state = KICKED; + SET_KICK_STATE(root_worker, KICKED); return grpc_wakeup_fd_wakeup(&global_wakeup_fd); } else if (next_worker->kick_state == UNKICKED) { GPR_ASSERT(next_worker->initialized_cv); - next_worker->kick_state = KICKED; + SET_KICK_STATE(next_worker, KICKED); gpr_cv_signal(&next_worker->cv); return GRPC_ERROR_NONE; + } else if (next_worker->kick_state == DESIGNATED_POLLER) { + if (root_worker->kick_state != DESIGNATED_POLLER) { + SET_KICK_STATE(root_worker, KICKED); + if (root_worker->initialized_cv) { + gpr_cv_signal(&root_worker->cv); + } + return GRPC_ERROR_NONE; + } else { + SET_KICK_STATE(next_worker, KICKED); + return grpc_wakeup_fd_wakeup(&global_wakeup_fd); + } } else { + GPR_ASSERT(next_worker->kick_state == KICKED); + SET_KICK_STATE(next_worker, KICKED); return GRPC_ERROR_NONE; } } else { + GPR_ASSERT(false); return GRPC_ERROR_NONE; } } else if (specific_worker->kick_state == KICKED) { return GRPC_ERROR_NONE; } else if (gpr_tls_get(&g_current_thread_worker) == (intptr_t)specific_worker) { - specific_worker->kick_state = KICKED; + SET_KICK_STATE(specific_worker, KICKED); return GRPC_ERROR_NONE; } else if (specific_worker == (grpc_pollset_worker *)gpr_atm_no_barrier_load(&g_active_poller)) { - specific_worker->kick_state = KICKED; + SET_KICK_STATE(specific_worker, KICKED); return grpc_wakeup_fd_wakeup(&global_wakeup_fd); } else if (specific_worker->initialized_cv) { - specific_worker->kick_state = KICKED; + SET_KICK_STATE(specific_worker, KICKED); gpr_cv_signal(&specific_worker->cv); return GRPC_ERROR_NONE; } else { - specific_worker->kick_state = KICKED; + SET_KICK_STATE(specific_worker, KICKED); return GRPC_ERROR_NONE; } } @@ -830,7 +860,7 @@ static void wq_sched(grpc_exec_ctx *exec_ctx, grpc_closure *closure, grpc_pollset_worker *inspect_worker = inspect->root_worker; do { if (inspect_worker->kick_state == UNKICKED) { - inspect_worker->kick_state = KICKED; + SET_KICK_STATE(inspect_worker, KICKED); grpc_closure_list_append( &inspect_worker->schedule_on_end_work, closure, error); if (inspect_worker->initialized_cv) { From b89bac0752c5c5fbd8e54db684062976c3a3365f Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 26 May 2017 15:20:32 +0000 Subject: [PATCH 006/127] Add tracing for epoll1 --- src/core/lib/iomgr/ev_epoll1_linux.c | 30 ++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/core/lib/iomgr/ev_epoll1_linux.c b/src/core/lib/iomgr/ev_epoll1_linux.c index 0f067b52a3a..ea755544c0b 100644 --- a/src/core/lib/iomgr/ev_epoll1_linux.c +++ b/src/core/lib/iomgr/ev_epoll1_linux.c @@ -61,6 +61,7 @@ #include "src/core/lib/iomgr/workqueue.h" #include "src/core/lib/profiling/timers.h" #include "src/core/lib/support/block_annotate.h" +#include "src/core/lib/support/string.h" static grpc_wakeup_fd global_wakeup_fd; static int g_epfd; @@ -744,45 +745,74 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, static grpc_error *pollset_kick(grpc_pollset *pollset, grpc_pollset_worker *specific_worker) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_strvec log; + gpr_strvec_init(&log); + char *tmp; + gpr_asprintf(&tmp, "PS:%p KICK:%p curps=%p curworker=%p root=%p", pollset, specific_worker, (void*)gpr_tls_get(&g_current_thread_pollset), (void*)gpr_tls_get(&g_current_thread_worker), pollset->root_worker); + gpr_strvec_add(&log, tmp); + if (pollset->root_worker != NULL) { + gpr_asprintf(&tmp, " {kicked=%d next=%p {kicked=%d}}", pollset->root_worker->kick_state, pollset->root_worker->next, pollset->root_worker->next->kick_state); + gpr_strvec_add(&log, tmp); + } + if (specific_worker != NULL) { + gpr_asprintf(&tmp, " worker_kicked=%d", specific_worker->kick_state); + gpr_strvec_add(&log, tmp); + } + tmp = gpr_strvec_flatten(&log, NULL); + gpr_strvec_destroy(&log); + gpr_log(GPR_DEBUG, "%s", tmp); + gpr_free(tmp); + } if (specific_worker == NULL) { if (gpr_tls_get(&g_current_thread_pollset) != (intptr_t)pollset) { grpc_pollset_worker *root_worker = pollset->root_worker; if (root_worker == NULL) { pollset->kicked_without_poller = true; + if (GRPC_TRACER_ON(grpc_polling_trace)) { gpr_log(GPR_DEBUG, " .. kicked_without_poller"); } return GRPC_ERROR_NONE; } grpc_pollset_worker *next_worker = root_worker->next; if (root_worker == next_worker && root_worker == (grpc_pollset_worker *)gpr_atm_no_barrier_load( &g_active_poller)) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { gpr_log(GPR_DEBUG, " .. kicked %p", root_worker); } root_worker->kick_state = KICKED; return grpc_wakeup_fd_wakeup(&global_wakeup_fd); } else if (next_worker->kick_state == UNKICKED) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { gpr_log(GPR_DEBUG, " .. kicked %p", next_worker); } GPR_ASSERT(next_worker->initialized_cv); next_worker->kick_state = KICKED; gpr_cv_signal(&next_worker->cv); return GRPC_ERROR_NONE; } else { + if (GRPC_TRACER_ON(grpc_polling_trace)) { gpr_log(GPR_DEBUG, " .. do nothing??"); } return GRPC_ERROR_NONE; } } else { + if (GRPC_TRACER_ON(grpc_polling_trace)) { gpr_log(GPR_DEBUG, " .. do nothing??"); } return GRPC_ERROR_NONE; } } else if (specific_worker->kick_state == KICKED) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { gpr_log(GPR_DEBUG, " .. specific worker already kicked"); } return GRPC_ERROR_NONE; } else if (gpr_tls_get(&g_current_thread_worker) == (intptr_t)specific_worker) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { gpr_log(GPR_DEBUG, " .. mark %p kicked", specific_worker); } specific_worker->kick_state = KICKED; return GRPC_ERROR_NONE; } else if (specific_worker == (grpc_pollset_worker *)gpr_atm_no_barrier_load(&g_active_poller)) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { gpr_log(GPR_DEBUG, " .. kick active poller"); } specific_worker->kick_state = KICKED; return grpc_wakeup_fd_wakeup(&global_wakeup_fd); } else if (specific_worker->initialized_cv) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { gpr_log(GPR_DEBUG, " .. kick waiting worker"); } specific_worker->kick_state = KICKED; gpr_cv_signal(&specific_worker->cv); return GRPC_ERROR_NONE; } else { + if (GRPC_TRACER_ON(grpc_polling_trace)) { gpr_log(GPR_DEBUG, " .. kick non-waiting worker"); } specific_worker->kick_state = KICKED; return GRPC_ERROR_NONE; } From dcb6262019ba22e36eaafcea089ef70e42325991 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 26 May 2017 09:47:38 -0700 Subject: [PATCH 007/127] Make race conditions more prevalent --- test/core/surface/completion_queue_threading_test.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/core/surface/completion_queue_threading_test.c b/test/core/surface/completion_queue_threading_test.c index bff69ec74fd..4ede629139f 100644 --- a/test/core/surface/completion_queue_threading_test.c +++ b/test/core/surface/completion_queue_threading_test.c @@ -205,7 +205,8 @@ static void consumer_thread(void *arg) { gpr_log(GPR_INFO, "consumer %d phase 2", opt->id); for (;;) { - ev = grpc_completion_queue_next(opt->cc, ten_seconds_time(), NULL); + ev = grpc_completion_queue_next(opt->cc, + gpr_inf_future(GPR_CLOCK_MONOTONIC), NULL); switch (ev.type) { case GRPC_OP_COMPLETE: GPR_ASSERT(ev.success); From c81512a2c548813a4db063f0ee6ab73edb84cfc0 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 26 May 2017 09:53:58 -0700 Subject: [PATCH 008/127] Fix race on shutdown --- src/core/lib/iomgr/ev_epoll1_linux.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/core/lib/iomgr/ev_epoll1_linux.c b/src/core/lib/iomgr/ev_epoll1_linux.c index effa9bde8a3..24f40ec040a 100644 --- a/src/core/lib/iomgr/ev_epoll1_linux.c +++ b/src/core/lib/iomgr/ev_epoll1_linux.c @@ -473,7 +473,9 @@ static void pollset_maybe_finish_shutdown(grpc_exec_ctx *exec_ctx, static void pollset_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_closure *closure) { GPR_ASSERT(pollset->shutdown_closure == NULL); + GPR_ASSERT(!pollset->shutting_down); pollset->shutdown_closure = closure; + pollset->shutting_down = true; GRPC_LOG_IF_ERROR("pollset_shutdown", pollset_kick_all(pollset)); pollset_maybe_finish_shutdown(exec_ctx, pollset); } @@ -600,8 +602,7 @@ static bool begin_worker(grpc_pollset *pollset, grpc_pollset_worker *worker, GPR_ASSERT(gpr_atm_no_barrier_load(&g_active_poller) != (gpr_atm)worker); worker->initialized_cv = true; gpr_cv_init(&worker->cv); - while (worker->kick_state == UNKICKED && - pollset->shutdown_closure == NULL) { + while (worker->kick_state == UNKICKED && !pollset->shutting_down) { if (gpr_cv_wait(&worker->cv, &pollset->mu, deadline) && worker->kick_state == UNKICKED) { SET_KICK_STATE(worker, KICKED); @@ -610,8 +611,7 @@ static bool begin_worker(grpc_pollset *pollset, grpc_pollset_worker *worker, *now = gpr_now(now->clock_type); } - return worker->kick_state == DESIGNATED_POLLER && - pollset->shutdown_closure == NULL; + return worker->kick_state == DESIGNATED_POLLER && !pollset->shutting_down; } static bool check_neighbourhood_for_available_poller( @@ -745,7 +745,7 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, gpr_tls_set(&g_current_thread_pollset, (intptr_t)pollset); if (begin_worker(pollset, &worker, worker_hdl, &now, deadline)) { gpr_tls_set(&g_current_thread_worker, (intptr_t)&worker); - GPR_ASSERT(!pollset->shutdown_closure); + GPR_ASSERT(!pollset->shutting_down); GPR_ASSERT(!pollset->seen_inactive); gpr_mu_unlock(&pollset->mu); append_error(&error, pollset_epoll(exec_ctx, pollset, now, deadline), From 3e7059bb6b90ebdb422daf6a1c94ada6c7821052 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 26 May 2017 13:57:54 -0700 Subject: [PATCH 009/127] Remove accidental debug --- src/core/lib/iomgr/ev_epoll1_linux.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core/lib/iomgr/ev_epoll1_linux.c b/src/core/lib/iomgr/ev_epoll1_linux.c index 24f40ec040a..5ac2d4d453f 100644 --- a/src/core/lib/iomgr/ev_epoll1_linux.c +++ b/src/core/lib/iomgr/ev_epoll1_linux.c @@ -836,7 +836,6 @@ static grpc_error *pollset_kick(grpc_pollset *pollset, return GRPC_ERROR_NONE; } } else { - GPR_ASSERT(false); return GRPC_ERROR_NONE; } } else if (specific_worker->kick_state == KICKED) { From ac0d6ca68aa0a860a4e86575907d7d0e42cf8406 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 31 May 2017 16:22:30 +0000 Subject: [PATCH 010/127] Fix compile --- src/core/lib/surface/completion_queue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/lib/surface/completion_queue.c b/src/core/lib/surface/completion_queue.c index 651afe685c3..b31ee2cd268 100644 --- a/src/core/lib/surface/completion_queue.c +++ b/src/core/lib/surface/completion_queue.c @@ -587,7 +587,7 @@ static void cq_end_op_for_next(grpc_exec_ctx *exec_ctx, /* Only kick if this is the first item queued */ if (is_first) { gpr_mu_lock(cqd->mu); - grpc_error *kick_error = cq->poller_vtable->kick(POLLSET_FROM_CQ(cq); + grpc_error *kick_error = cq->poller_vtable->kick(POLLSET_FROM_CQ(cq), NULL); gpr_mu_unlock(cqd->mu); if (kick_error != GRPC_ERROR_NONE) { From 830e82ad122fbdbe8bcb5cd09b333fcb4515d452 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 31 May 2017 16:26:27 -0700 Subject: [PATCH 011/127] Fixes, debug --- src/core/lib/iomgr/ev_epoll1_linux.c | 129 ++++++++++++++---- .../iomgr/ev_epoll_limited_pollers_linux.c | 8 +- .../lib/iomgr/ev_epoll_thread_pool_linux.c | 8 +- src/core/lib/iomgr/ev_epollex_linux.c | 8 +- src/core/lib/iomgr/ev_epollsig_linux.c | 8 +- src/core/lib/iomgr/lockfree_event.c | 14 +- src/core/lib/iomgr/lockfree_event.h | 5 +- 7 files changed, 130 insertions(+), 50 deletions(-) diff --git a/src/core/lib/iomgr/ev_epoll1_linux.c b/src/core/lib/iomgr/ev_epoll1_linux.c index 5ac2d4d453f..379b8750145 100644 --- a/src/core/lib/iomgr/ev_epoll1_linux.c +++ b/src/core/lib/iomgr/ev_epoll1_linux.c @@ -94,6 +94,18 @@ static void fd_global_shutdown(void); typedef enum { UNKICKED, KICKED, DESIGNATED_POLLER } kick_state; +static const char *kick_state_string(kick_state st) { + switch (st) { + case UNKICKED: + return "UNKICKED"; + case KICKED: + return "KICKED"; + case DESIGNATED_POLLER: + return "DESIGNATED_POLLER"; + } + GPR_UNREACHABLE_CODE(return "UNKNOWN"); +} + struct grpc_pollset_worker { kick_state kick_state; int kick_state_mutator; // which line of code last changed kick state @@ -217,7 +229,7 @@ static grpc_fd *fd_create(int fd, const char *name) { gpr_asprintf(&fd_name, "%s fd=%d", name, fd); grpc_iomgr_register_object(&new_fd->iomgr_object, fd_name); #ifdef GRPC_FD_REF_COUNT_DEBUG - gpr_log(GPR_DEBUG, "FD %d %p create %s", fd, (void *)new_fd, fd_name); + gpr_log(GPR_ERROR, "FD %d %p create %s", fd, (void *)new_fd, fd_name); #endif gpr_free(fd_name); @@ -283,12 +295,12 @@ static bool fd_is_shutdown(grpc_fd *fd) { static void fd_notify_on_read(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure *closure) { - grpc_lfev_notify_on(exec_ctx, &fd->read_closure, closure); + grpc_lfev_notify_on(exec_ctx, &fd->read_closure, closure, "read"); } static void fd_notify_on_write(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure *closure) { - grpc_lfev_notify_on(exec_ctx, &fd->write_closure, closure); + grpc_lfev_notify_on(exec_ctx, &fd->write_closure, closure, "write"); } static grpc_workqueue *fd_get_workqueue(grpc_fd *fd) { @@ -297,7 +309,7 @@ static grpc_workqueue *fd_get_workqueue(grpc_fd *fd) { static void fd_become_readable(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_pollset *notifier) { - grpc_lfev_set_ready(exec_ctx, &fd->read_closure); + grpc_lfev_set_ready(exec_ctx, &fd->read_closure, "read"); /* Note, it is possible that fd_become_readable might be called twice with different 'notifier's when an fd becomes readable and it is in two epoll @@ -309,7 +321,7 @@ static void fd_become_readable(grpc_exec_ctx *exec_ctx, grpc_fd *fd, } static void fd_become_writable(grpc_exec_ctx *exec_ctx, grpc_fd *fd) { - grpc_lfev_set_ready(exec_ctx, &fd->write_closure); + grpc_lfev_set_ready(exec_ctx, &fd->write_closure, "write"); } /******************************************************************************* @@ -555,6 +567,10 @@ static bool begin_worker(grpc_pollset *pollset, grpc_pollset_worker *worker, worker->schedule_on_end_work = (grpc_closure_list)GRPC_CLOSURE_LIST_INIT; pollset->begin_refs++; + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_ERROR, "PS:%p BEGIN_STARTS:%p", pollset, worker); + } + if (pollset->seen_inactive) { // pollset has been observed to be inactive, we need to move back to the // active list @@ -570,6 +586,11 @@ static bool begin_worker(grpc_pollset *pollset, grpc_pollset_worker *worker, retry_lock_neighbourhood: gpr_mu_lock(&neighbourhood->mu); gpr_mu_lock(&pollset->mu); + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_ERROR, "PS:%p BEGIN_REORG:%p kick_state=%s is_reassigning=%d", + pollset, worker, kick_state_string(worker->kick_state), + is_reassigning); + } if (pollset->seen_inactive) { if (neighbourhood != pollset->neighbourhood) { gpr_mu_unlock(&neighbourhood->mu); @@ -603,6 +624,11 @@ static bool begin_worker(grpc_pollset *pollset, grpc_pollset_worker *worker, worker->initialized_cv = true; gpr_cv_init(&worker->cv); while (worker->kick_state == UNKICKED && !pollset->shutting_down) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_ERROR, "PS:%p BEGIN_WAIT:%p kick_state=%s shutdown=%d", + pollset, worker, kick_state_string(worker->kick_state), + pollset->shutting_down); + } if (gpr_cv_wait(&worker->cv, &pollset->mu, deadline) && worker->kick_state == UNKICKED) { SET_KICK_STATE(worker, KICKED); @@ -610,6 +636,11 @@ static bool begin_worker(grpc_pollset *pollset, grpc_pollset_worker *worker, } *now = gpr_now(now->clock_type); } + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_ERROR, "PS:%p BEGIN_DONE:%p kick_state=%s shutdown=%d", pollset, + worker, kick_state_string(worker->kick_state), + pollset->shutting_down); + } return worker->kick_state == DESIGNATED_POLLER && !pollset->shutting_down; } @@ -631,10 +662,18 @@ static bool check_neighbourhood_for_available_poller( case UNKICKED: if (gpr_atm_no_barrier_cas(&g_active_poller, 0, (gpr_atm)inspect_worker)) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, " .. choose next poller to be %p", + inspect_worker); + } SET_KICK_STATE(inspect_worker, DESIGNATED_POLLER); if (inspect_worker->initialized_cv) { gpr_cv_signal(&inspect_worker->cv); } + } else { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, " .. beaten to choose next poller"); + } } // even if we didn't win the cas, there's a worker, we can stop found_worker = true; @@ -647,9 +686,12 @@ static bool check_neighbourhood_for_available_poller( break; } inspect_worker = inspect_worker->next; - } while (inspect_worker != inspect->root_worker); + } while (!found_worker && inspect_worker != inspect->root_worker); } if (!found_worker) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, " .. mark pollset %p inactive", inspect); + } inspect->seen_inactive = true; if (inspect == neighbourhood->active_root) { neighbourhood->active_root = @@ -667,12 +709,19 @@ static bool check_neighbourhood_for_available_poller( static void end_worker(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_pollset_worker *worker, grpc_pollset_worker **worker_hdl) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, "PS:%p END_WORKER:%p", pollset, worker); + } if (worker_hdl != NULL) *worker_hdl = NULL; + /* Make sure we appear kicked */ SET_KICK_STATE(worker, KICKED); grpc_closure_list_move(&worker->schedule_on_end_work, &exec_ctx->closure_list); if (gpr_atm_no_barrier_load(&g_active_poller) == (gpr_atm)worker) { if (worker->next != worker && worker->next->kick_state == UNKICKED) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, " .. choose next poller to be peer %p", worker); + } GPR_ASSERT(worker->next->initialized_cv); gpr_atm_no_barrier_store(&g_active_poller, (gpr_atm)worker->next); SET_KICK_STATE(worker->next, DESIGNATED_POLLER); @@ -722,6 +771,9 @@ static void end_worker(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, if (worker->initialized_cv) { gpr_cv_destroy(&worker->cv); } + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, " .. remove worker"); + } if (EMPTIED == worker_remove(pollset, worker)) { pollset_maybe_finish_shutdown(exec_ctx, pollset); } @@ -742,8 +794,8 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, pollset->kicked_without_poller = false; return GRPC_ERROR_NONE; } - gpr_tls_set(&g_current_thread_pollset, (intptr_t)pollset); if (begin_worker(pollset, &worker, worker_hdl, &now, deadline)) { + gpr_tls_set(&g_current_thread_pollset, (intptr_t)pollset); gpr_tls_set(&g_current_thread_worker, (intptr_t)&worker); GPR_ASSERT(!pollset->shutting_down); GPR_ASSERT(!pollset->seen_inactive); @@ -752,6 +804,8 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, err_desc); gpr_mu_lock(&pollset->mu); gpr_tls_set(&g_current_thread_worker, 0); + } else { + gpr_tls_set(&g_current_thread_pollset, (intptr_t)pollset); } end_worker(exec_ctx, pollset, &worker, worker_hdl); gpr_tls_set(&g_current_thread_pollset, 0); @@ -770,18 +824,20 @@ static grpc_error *pollset_kick(grpc_pollset *pollset, (void *)gpr_tls_get(&g_current_thread_worker), pollset->root_worker); gpr_strvec_add(&log, tmp); if (pollset->root_worker != NULL) { - gpr_asprintf(&tmp, " {kicked=%d next=%p {kicked=%d}}", - pollset->root_worker->kick_state, pollset->root_worker->next, - pollset->root_worker->next->kick_state); + gpr_asprintf(&tmp, " {kick_state=%s next=%p {kick_state=%s}}", + kick_state_string(pollset->root_worker->kick_state), + pollset->root_worker->next, + kick_state_string(pollset->root_worker->next->kick_state)); gpr_strvec_add(&log, tmp); } if (specific_worker != NULL) { - gpr_asprintf(&tmp, " worker_kicked=%d", specific_worker->kick_state); + gpr_asprintf(&tmp, " worker_kick_state=%s", + kick_state_string(specific_worker->kick_state)); gpr_strvec_add(&log, tmp); } tmp = gpr_strvec_flatten(&log, NULL); gpr_strvec_destroy(&log); - gpr_log(GPR_DEBUG, "%s", tmp); + gpr_log(GPR_ERROR, "%s", tmp); gpr_free(tmp); } if (specific_worker == NULL) { @@ -790,23 +846,36 @@ static grpc_error *pollset_kick(grpc_pollset *pollset, if (root_worker == NULL) { pollset->kicked_without_poller = true; if (GRPC_TRACER_ON(grpc_polling_trace)) { - gpr_log(GPR_DEBUG, " .. kicked_without_poller"); + gpr_log(GPR_ERROR, " .. kicked_without_poller"); } return GRPC_ERROR_NONE; } grpc_pollset_worker *next_worker = root_worker->next; - if (root_worker == next_worker && // only try and wake up a poller if - // there is no next worker - root_worker == (grpc_pollset_worker *)gpr_atm_no_barrier_load( - &g_active_poller)) { + if (root_worker->kick_state == KICKED) { if (GRPC_TRACER_ON(grpc_polling_trace)) { - gpr_log(GPR_DEBUG, " .. kicked %p", root_worker); + gpr_log(GPR_ERROR, " .. already kicked %p", root_worker); + } + SET_KICK_STATE(root_worker, KICKED); + return GRPC_ERROR_NONE; + } else if (next_worker->kick_state == KICKED) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_ERROR, " .. already kicked %p", next_worker); + } + SET_KICK_STATE(next_worker, KICKED); + return GRPC_ERROR_NONE; + } else if (root_worker == + next_worker && // only try and wake up a poller if + // there is no next worker + root_worker == (grpc_pollset_worker *)gpr_atm_no_barrier_load( + &g_active_poller)) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_ERROR, " .. kicked %p", root_worker); } SET_KICK_STATE(root_worker, KICKED); return grpc_wakeup_fd_wakeup(&global_wakeup_fd); } else if (next_worker->kick_state == UNKICKED) { if (GRPC_TRACER_ON(grpc_polling_trace)) { - gpr_log(GPR_DEBUG, " .. kicked %p", next_worker); + gpr_log(GPR_ERROR, " .. kicked %p", next_worker); } GPR_ASSERT(next_worker->initialized_cv); SET_KICK_STATE(next_worker, KICKED); @@ -815,7 +884,10 @@ static grpc_error *pollset_kick(grpc_pollset *pollset, } else if (next_worker->kick_state == DESIGNATED_POLLER) { if (root_worker->kick_state != DESIGNATED_POLLER) { if (GRPC_TRACER_ON(grpc_polling_trace)) { - gpr_log(GPR_DEBUG, " .. kicked root non-poller %p", next_worker); + gpr_log( + GPR_ERROR, + " .. kicked root non-poller %p (initialized_cv=%d) (poller=%p)", + root_worker, root_worker->initialized_cv, next_worker); } SET_KICK_STATE(root_worker, KICKED); if (root_worker->initialized_cv) { @@ -824,7 +896,7 @@ static grpc_error *pollset_kick(grpc_pollset *pollset, return GRPC_ERROR_NONE; } else { if (GRPC_TRACER_ON(grpc_polling_trace)) { - gpr_log(GPR_DEBUG, " .. non-root poller %p (root=%p)", next_worker, + gpr_log(GPR_ERROR, " .. non-root poller %p (root=%p)", next_worker, root_worker); } SET_KICK_STATE(next_worker, KICKED); @@ -836,37 +908,40 @@ static grpc_error *pollset_kick(grpc_pollset *pollset, return GRPC_ERROR_NONE; } } else { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_ERROR, " .. kicked while waking up"); + } return GRPC_ERROR_NONE; } } else if (specific_worker->kick_state == KICKED) { if (GRPC_TRACER_ON(grpc_polling_trace)) { - gpr_log(GPR_DEBUG, " .. specific worker already kicked"); + gpr_log(GPR_ERROR, " .. specific worker already kicked"); } return GRPC_ERROR_NONE; } else if (gpr_tls_get(&g_current_thread_worker) == (intptr_t)specific_worker) { if (GRPC_TRACER_ON(grpc_polling_trace)) { - gpr_log(GPR_DEBUG, " .. mark %p kicked", specific_worker); + gpr_log(GPR_ERROR, " .. mark %p kicked", specific_worker); } SET_KICK_STATE(specific_worker, KICKED); return GRPC_ERROR_NONE; } else if (specific_worker == (grpc_pollset_worker *)gpr_atm_no_barrier_load(&g_active_poller)) { if (GRPC_TRACER_ON(grpc_polling_trace)) { - gpr_log(GPR_DEBUG, " .. kick active poller"); + gpr_log(GPR_ERROR, " .. kick active poller"); } SET_KICK_STATE(specific_worker, KICKED); return grpc_wakeup_fd_wakeup(&global_wakeup_fd); } else if (specific_worker->initialized_cv) { if (GRPC_TRACER_ON(grpc_polling_trace)) { - gpr_log(GPR_DEBUG, " .. kick waiting worker"); + gpr_log(GPR_ERROR, " .. kick waiting worker"); } SET_KICK_STATE(specific_worker, KICKED); gpr_cv_signal(&specific_worker->cv); return GRPC_ERROR_NONE; } else { if (GRPC_TRACER_ON(grpc_polling_trace)) { - gpr_log(GPR_DEBUG, " .. kick non-waiting worker"); + gpr_log(GPR_ERROR, " .. kick non-waiting worker"); } SET_KICK_STATE(specific_worker, KICKED); return GRPC_ERROR_NONE; @@ -1051,6 +1126,8 @@ const grpc_event_engine_vtable *grpc_init_epoll1_linux(bool explicit_request) { return NULL; } + gpr_log(GPR_ERROR, "grpc epoll fd: %d", g_epfd); + return &vtable; } diff --git a/src/core/lib/iomgr/ev_epoll_limited_pollers_linux.c b/src/core/lib/iomgr/ev_epoll_limited_pollers_linux.c index d23bf6c06cb..4a17f7d07c4 100644 --- a/src/core/lib/iomgr/ev_epoll_limited_pollers_linux.c +++ b/src/core/lib/iomgr/ev_epoll_limited_pollers_linux.c @@ -1145,12 +1145,12 @@ static void fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_error *why) { static void fd_notify_on_read(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure *closure) { - grpc_lfev_notify_on(exec_ctx, &fd->read_closure, closure); + grpc_lfev_notify_on(exec_ctx, &fd->read_closure, closure, "read"); } static void fd_notify_on_write(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure *closure) { - grpc_lfev_notify_on(exec_ctx, &fd->write_closure, closure); + grpc_lfev_notify_on(exec_ctx, &fd->write_closure, closure, "write"); } static grpc_workqueue *fd_get_workqueue(grpc_fd *fd) { @@ -1369,7 +1369,7 @@ static int poll_deadline_to_millis_timeout(gpr_timespec deadline, static void fd_become_readable(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_pollset *notifier) { - grpc_lfev_set_ready(exec_ctx, &fd->read_closure); + grpc_lfev_set_ready(exec_ctx, &fd->read_closure, "read"); /* Note, it is possible that fd_become_readable might be called twice with different 'notifier's when an fd becomes readable and it is in two epoll @@ -1381,7 +1381,7 @@ static void fd_become_readable(grpc_exec_ctx *exec_ctx, grpc_fd *fd, } static void fd_become_writable(grpc_exec_ctx *exec_ctx, grpc_fd *fd) { - grpc_lfev_set_ready(exec_ctx, &fd->write_closure); + grpc_lfev_set_ready(exec_ctx, &fd->write_closure, "write"); } static void pollset_release_polling_island(grpc_exec_ctx *exec_ctx, diff --git a/src/core/lib/iomgr/ev_epoll_thread_pool_linux.c b/src/core/lib/iomgr/ev_epoll_thread_pool_linux.c index bb44321922a..adc5e796440 100644 --- a/src/core/lib/iomgr/ev_epoll_thread_pool_linux.c +++ b/src/core/lib/iomgr/ev_epoll_thread_pool_linux.c @@ -672,12 +672,12 @@ static void fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_error *why) { static void fd_notify_on_read(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure *closure) { - grpc_lfev_notify_on(exec_ctx, &fd->read_closure, closure); + grpc_lfev_notify_on(exec_ctx, &fd->read_closure, closure, "read"); } static void fd_notify_on_write(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure *closure) { - grpc_lfev_notify_on(exec_ctx, &fd->write_closure, closure); + grpc_lfev_notify_on(exec_ctx, &fd->write_closure, closure, "write"); } static grpc_workqueue *fd_get_workqueue(grpc_fd *fd) { return NULL; } @@ -810,11 +810,11 @@ static void pollset_init(grpc_pollset *pollset, gpr_mu **mu) { } static void fd_become_readable(grpc_exec_ctx *exec_ctx, grpc_fd *fd) { - grpc_lfev_set_ready(exec_ctx, &fd->read_closure); + grpc_lfev_set_ready(exec_ctx, &fd->read_closure, "read"); } static void fd_become_writable(grpc_exec_ctx *exec_ctx, grpc_fd *fd) { - grpc_lfev_set_ready(exec_ctx, &fd->write_closure); + grpc_lfev_set_ready(exec_ctx, &fd->write_closure, "write"); } static void pollset_release_epoll_set(grpc_exec_ctx *exec_ctx, grpc_pollset *ps, diff --git a/src/core/lib/iomgr/ev_epollex_linux.c b/src/core/lib/iomgr/ev_epollex_linux.c index 7cb6085e255..b0d1a93886c 100644 --- a/src/core/lib/iomgr/ev_epollex_linux.c +++ b/src/core/lib/iomgr/ev_epollex_linux.c @@ -438,12 +438,12 @@ static void fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_error *why) { static void fd_notify_on_read(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure *closure) { - grpc_lfev_notify_on(exec_ctx, &fd->read_closure, closure); + grpc_lfev_notify_on(exec_ctx, &fd->read_closure, closure, "read"); } static void fd_notify_on_write(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure *closure) { - grpc_lfev_notify_on(exec_ctx, &fd->write_closure, closure); + grpc_lfev_notify_on(exec_ctx, &fd->write_closure, closure, "write"); } static grpc_workqueue *fd_get_workqueue(grpc_fd *fd) { @@ -780,7 +780,7 @@ static int poll_deadline_to_millis_timeout(gpr_timespec deadline, static void fd_become_readable(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_pollset *notifier) { - grpc_lfev_set_ready(exec_ctx, &fd->read_closure); + grpc_lfev_set_ready(exec_ctx, &fd->read_closure, "read"); /* Note, it is possible that fd_become_readable might be called twice with different 'notifier's when an fd becomes readable and it is in two epoll @@ -792,7 +792,7 @@ static void fd_become_readable(grpc_exec_ctx *exec_ctx, grpc_fd *fd, } static void fd_become_writable(grpc_exec_ctx *exec_ctx, grpc_fd *fd) { - grpc_lfev_set_ready(exec_ctx, &fd->write_closure); + grpc_lfev_set_ready(exec_ctx, &fd->write_closure, "write"); } static grpc_error *fd_become_pollable_locked(grpc_fd *fd) { diff --git a/src/core/lib/iomgr/ev_epollsig_linux.c b/src/core/lib/iomgr/ev_epollsig_linux.c index 25a4d32cfc5..2f61cd5164c 100644 --- a/src/core/lib/iomgr/ev_epollsig_linux.c +++ b/src/core/lib/iomgr/ev_epollsig_linux.c @@ -1073,12 +1073,12 @@ static void fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_error *why) { static void fd_notify_on_read(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure *closure) { - grpc_lfev_notify_on(exec_ctx, &fd->read_closure, closure); + grpc_lfev_notify_on(exec_ctx, &fd->read_closure, closure, "read"); } static void fd_notify_on_write(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure *closure) { - grpc_lfev_notify_on(exec_ctx, &fd->write_closure, closure); + grpc_lfev_notify_on(exec_ctx, &fd->write_closure, closure, "write"); } static grpc_workqueue *fd_get_workqueue(grpc_fd *fd) { @@ -1263,7 +1263,7 @@ static int poll_deadline_to_millis_timeout(gpr_timespec deadline, static void fd_become_readable(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_pollset *notifier) { - grpc_lfev_set_ready(exec_ctx, &fd->read_closure); + grpc_lfev_set_ready(exec_ctx, &fd->read_closure, "read"); /* Note, it is possible that fd_become_readable might be called twice with different 'notifier's when an fd becomes readable and it is in two epoll @@ -1275,7 +1275,7 @@ static void fd_become_readable(grpc_exec_ctx *exec_ctx, grpc_fd *fd, } static void fd_become_writable(grpc_exec_ctx *exec_ctx, grpc_fd *fd) { - grpc_lfev_set_ready(exec_ctx, &fd->write_closure); + grpc_lfev_set_ready(exec_ctx, &fd->write_closure, "write"); } static void pollset_release_polling_island(grpc_exec_ctx *exec_ctx, diff --git a/src/core/lib/iomgr/lockfree_event.c b/src/core/lib/iomgr/lockfree_event.c index 898ec1cb1bf..722031a5dab 100644 --- a/src/core/lib/iomgr/lockfree_event.c +++ b/src/core/lib/iomgr/lockfree_event.c @@ -94,12 +94,12 @@ bool grpc_lfev_is_shutdown(gpr_atm *state) { } void grpc_lfev_notify_on(grpc_exec_ctx *exec_ctx, gpr_atm *state, - grpc_closure *closure) { + grpc_closure *closure, const char *variable) { while (true) { gpr_atm curr = gpr_atm_no_barrier_load(state); if (GRPC_TRACER_ON(grpc_polling_trace)) { - gpr_log(GPR_DEBUG, "lfev_notify_on: %p curr=%p closure=%p", state, - (void *)curr, closure); + gpr_log(GPR_ERROR, "lfev_notify_on[%s]: %p curr=%p closure=%p", variable, + state, (void *)curr, closure); } switch (curr) { case CLOSURE_NOT_READY: { @@ -164,7 +164,7 @@ bool grpc_lfev_set_shutdown(grpc_exec_ctx *exec_ctx, gpr_atm *state, while (true) { gpr_atm curr = gpr_atm_no_barrier_load(state); if (GRPC_TRACER_ON(grpc_polling_trace)) { - gpr_log(GPR_DEBUG, "lfev_set_shutdown: %p curr=%p err=%s", state, + gpr_log(GPR_ERROR, "lfev_set_shutdown: %p curr=%p err=%s", state, (void *)curr, grpc_error_string(shutdown_err)); } switch (curr) { @@ -208,12 +208,14 @@ bool grpc_lfev_set_shutdown(grpc_exec_ctx *exec_ctx, gpr_atm *state, GPR_UNREACHABLE_CODE(return false); } -void grpc_lfev_set_ready(grpc_exec_ctx *exec_ctx, gpr_atm *state) { +void grpc_lfev_set_ready(grpc_exec_ctx *exec_ctx, gpr_atm *state, + const char *variable) { while (true) { gpr_atm curr = gpr_atm_no_barrier_load(state); if (GRPC_TRACER_ON(grpc_polling_trace)) { - gpr_log(GPR_DEBUG, "lfev_set_ready: %p curr=%p", state, (void *)curr); + gpr_log(GPR_ERROR, "lfev_set_ready[%s]: %p curr=%p", variable, state, + (void *)curr); } switch (curr) { diff --git a/src/core/lib/iomgr/lockfree_event.h b/src/core/lib/iomgr/lockfree_event.h index 1d9119204ca..89b3d8cf229 100644 --- a/src/core/lib/iomgr/lockfree_event.h +++ b/src/core/lib/iomgr/lockfree_event.h @@ -45,10 +45,11 @@ void grpc_lfev_destroy(gpr_atm *state); bool grpc_lfev_is_shutdown(gpr_atm *state); void grpc_lfev_notify_on(grpc_exec_ctx *exec_ctx, gpr_atm *state, - grpc_closure *closure); + grpc_closure *closure, const char *variable); /* Returns true on first successful shutdown */ bool grpc_lfev_set_shutdown(grpc_exec_ctx *exec_ctx, gpr_atm *state, grpc_error *shutdown_err); -void grpc_lfev_set_ready(grpc_exec_ctx *exec_ctx, gpr_atm *state); +void grpc_lfev_set_ready(grpc_exec_ctx *exec_ctx, gpr_atm *state, + const char *variable); #endif /* GRPC_CORE_LIB_IOMGR_LOCKFREE_EVENT_H */ From 148970b2aa0d2b86932b9332744b5d6c19d77c89 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Tue, 6 Jun 2017 15:39:39 +0000 Subject: [PATCH 012/127] Fix test --- test/core/surface/completion_queue_test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/core/surface/completion_queue_test.c b/test/core/surface/completion_queue_test.c index 35bda5b6418..6fee4c55233 100644 --- a/test/core/surface/completion_queue_test.c +++ b/test/core/surface/completion_queue_test.c @@ -108,7 +108,7 @@ static void test_pollset_conversion(void) { attr.cq_polling_type = polling_types[j]; cq = grpc_completion_queue_create( grpc_completion_queue_factory_lookup(&attr), &attr, NULL); - GPR_ASSERT(grpc_cq_from_pollset(grpc_cq_pollset(cq)) == cq); + GPR_ASSERT(grpc_cq_pollset(cq) != NULL); shutdown_and_destroy(cq); } } From 4cc2b9accae8f505f05d79ebc91622757ac6ac92 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Thu, 6 Jul 2017 08:29:45 -0700 Subject: [PATCH 013/127] Fix accidental boringssl change --- third_party/boringssl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/third_party/boringssl b/third_party/boringssl index 78684e5b222..be2ee342d37 160000 --- a/third_party/boringssl +++ b/third_party/boringssl @@ -1 +1 @@ -Subproject commit 78684e5b222645828ca302e56b40b9daff2b2d27 +Subproject commit be2ee342d3781ddb954f91f8a7e660c6f59e87e5 From 367c2c0eab9c82c04031fa977b40c41626f46d74 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Mon, 10 Jul 2017 11:21:24 -0700 Subject: [PATCH 014/127] Update protoc version --- src/objective-c/!ProtoCompiler-gRPCPlugin.podspec | 2 +- src/objective-c/!ProtoCompiler.podspec | 2 +- .../src/objective-c/!ProtoCompiler-gRPCPlugin.podspec.template | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec b/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec index 351a45df58e..b351d30aee1 100644 --- a/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec +++ b/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec @@ -101,7 +101,7 @@ Pod::Spec.new do |s| s.preserve_paths = plugin # Restrict the protoc version to the one supported by this plugin. - s.dependency '!ProtoCompiler', '3.2.0' + s.dependency '!ProtoCompiler', '3.3.0' # For the Protobuf dependency not to complain: s.ios.deployment_target = '7.0' s.osx.deployment_target = '10.9' diff --git a/src/objective-c/!ProtoCompiler.podspec b/src/objective-c/!ProtoCompiler.podspec index 2e9b944f33d..c3f95f9f425 100644 --- a/src/objective-c/!ProtoCompiler.podspec +++ b/src/objective-c/!ProtoCompiler.podspec @@ -36,7 +36,7 @@ Pod::Spec.new do |s| # exclamation mark ensures that other "regular" pods will be able to find it as it'll be installed # before them. s.name = '!ProtoCompiler' - v = '3.2.0' + v = '3.3.0' s.version = v s.summary = 'The Protobuf Compiler (protoc) generates Objective-C files from .proto files' s.description = <<-DESC diff --git a/templates/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec.template b/templates/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec.template index 93e3de8757d..9df980dc061 100644 --- a/templates/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec.template +++ b/templates/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec.template @@ -103,7 +103,7 @@ s.preserve_paths = plugin # Restrict the protoc version to the one supported by this plugin. - s.dependency '!ProtoCompiler', '3.2.0' + s.dependency '!ProtoCompiler', '3.3.0' # For the Protobuf dependency not to complain: s.ios.deployment_target = '7.0' s.osx.deployment_target = '10.9' From c0d3babbaad9ccf1630fafbc1e5f29ad2e8edd8a Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Mon, 10 Jul 2017 11:21:37 -0700 Subject: [PATCH 015/127] Update BoringSSL version --- gRPC-Core.podspec | 2 +- src/objective-c/BoringSSL.podspec | 542 ++++++++++++++------------- templates/gRPC-Core.podspec.template | 2 +- 3 files changed, 281 insertions(+), 265 deletions(-) diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec index 2095c0f5297..facc1c3b21f 100644 --- a/gRPC-Core.podspec +++ b/gRPC-Core.podspec @@ -176,7 +176,7 @@ Pod::Spec.new do |s| ss.header_mappings_dir = '.' ss.libraries = 'z' ss.dependency "#{s.name}/Interface", version - ss.dependency 'BoringSSL', '~> 8.0' + ss.dependency 'BoringSSL', '~> 9.0' ss.dependency 'nanopb', '~> 0.3' # To save you from scrolling, this is the last part of the podspec. diff --git a/src/objective-c/BoringSSL.podspec b/src/objective-c/BoringSSL.podspec index 651bd4977d8..81e6555cfd2 100644 --- a/src/objective-c/BoringSSL.podspec +++ b/src/objective-c/BoringSSL.podspec @@ -31,7 +31,7 @@ Pod::Spec.new do |s| s.name = 'BoringSSL' - version = '8.2' + version = '9.0' s.version = version s.summary = 'BoringSSL is a fork of OpenSSL that is designed to meet Google’s needs.' # Adapted from the homepage: @@ -69,9 +69,7 @@ Pod::Spec.new do |s| s.source = { :git => 'https://boringssl.googlesource.com/boringssl', - # Restore this version name hack in the next version!! - # :tag => "version_for_cocoapods_#{version}", - :tag => "version_for_cocoapods_8.0", + :tag => "version_for_cocoapods_#{version}", } name = 'openssl' @@ -389,42 +387,42 @@ Pod::Spec.new do |s| 0x28340c19, 0x283480ac, 0x283500ea, - 0x2c3228ca, - 0x2c32a8d8, - 0x2c3328ea, - 0x2c33a8fc, - 0x2c342910, - 0x2c34a922, - 0x2c35293d, - 0x2c35a94f, - 0x2c362962, + 0x2c3229b1, + 0x2c32a9bf, + 0x2c3329d1, + 0x2c33a9e3, + 0x2c3429f7, + 0x2c34aa09, + 0x2c352a24, + 0x2c35aa36, + 0x2c362a49, 0x2c36832d, - 0x2c37296f, - 0x2c37a981, - 0x2c382994, - 0x2c38a9ab, - 0x2c3929b9, - 0x2c39a9c9, - 0x2c3a29db, - 0x2c3aa9ef, - 0x2c3b2a00, - 0x2c3baa1f, - 0x2c3c2a33, - 0x2c3caa49, - 0x2c3d2a62, - 0x2c3daa7f, - 0x2c3e2a90, - 0x2c3eaa9e, - 0x2c3f2ab6, - 0x2c3faace, - 0x2c402adb, + 0x2c372a56, + 0x2c37aa68, + 0x2c382a7b, + 0x2c38aa92, + 0x2c392aa0, + 0x2c39aab0, + 0x2c3a2ac2, + 0x2c3aaad6, + 0x2c3b2ae7, + 0x2c3bab06, + 0x2c3c2b1a, + 0x2c3cab30, + 0x2c3d2b49, + 0x2c3dab66, + 0x2c3e2b77, + 0x2c3eab85, + 0x2c3f2b9d, + 0x2c3fabb5, + 0x2c402bc2, 0x2c4090e7, - 0x2c412aec, - 0x2c41aaff, + 0x2c412bd3, + 0x2c41abe6, 0x2c4210c0, - 0x2c42ab10, + 0x2c42abf7, 0x2c430720, - 0x2c43aa11, + 0x2c43aaf8, 0x30320000, 0x30328015, 0x3033001f, @@ -577,180 +575,189 @@ Pod::Spec.new do |s| 0x403b9861, 0x403c0064, 0x403c8083, - 0x403d18aa, - 0x403d98c0, - 0x403e18cf, - 0x403e98e2, - 0x403f18fc, - 0x403f990a, - 0x4040191f, - 0x40409933, - 0x40411950, - 0x4041996b, - 0x40421984, - 0x40429997, - 0x404319ab, - 0x404399c3, - 0x404419da, + 0x403d18c1, + 0x403d98d7, + 0x403e18e6, + 0x403e98f9, + 0x403f1913, + 0x403f9921, + 0x40401936, + 0x4040994a, + 0x40411967, + 0x40419982, + 0x4042199b, + 0x404299ae, + 0x404319c2, + 0x404399da, + 0x404419f1, 0x404480ac, - 0x404519ef, - 0x40459a01, - 0x40461a25, - 0x40469a45, - 0x40471a53, - 0x40479a7a, - 0x40481ab7, - 0x40489ad0, - 0x40491ae7, - 0x40499b01, - 0x404a1b18, - 0x404a9b36, - 0x404b1b4e, - 0x404b9b65, - 0x404c1b7b, - 0x404c9b8d, - 0x404d1bae, - 0x404d9bd0, - 0x404e1be4, - 0x404e9bf1, - 0x404f1c1e, - 0x404f9c47, - 0x40501c71, - 0x40509c85, - 0x40511ca0, - 0x40519cb0, - 0x40521cc7, - 0x40529ceb, - 0x40531d03, - 0x40539d16, - 0x40541d2b, - 0x40549d4e, - 0x40551d5c, - 0x40559d79, - 0x40561d86, - 0x40569d9f, - 0x40571db7, - 0x40579dca, - 0x40581ddf, - 0x40589e06, - 0x40591e35, - 0x40599e62, - 0x405a1e76, - 0x405a9e86, - 0x405b1e9e, - 0x405b9eaf, - 0x405c1ec2, - 0x405c9ed3, - 0x405d1ee0, - 0x405d9ef7, - 0x405e1f17, + 0x40451a06, + 0x40459a18, + 0x40461a3c, + 0x40469a5c, + 0x40471a6a, + 0x40479a91, + 0x40481ace, + 0x40489ae7, + 0x40491afe, + 0x40499b18, + 0x404a1b2f, + 0x404a9b4d, + 0x404b1b65, + 0x404b9b7c, + 0x404c1b92, + 0x404c9ba4, + 0x404d1bc5, + 0x404d9be7, + 0x404e1bfb, + 0x404e9c08, + 0x404f1c35, + 0x404f9c5e, + 0x40501c99, + 0x40509cad, + 0x40511cc8, + 0x40519cd8, + 0x40521cef, + 0x40529d13, + 0x40531d2b, + 0x40539d3e, + 0x40541d53, + 0x40549d76, + 0x40551d84, + 0x40559da1, + 0x40561dae, + 0x40569dc7, + 0x40571ddf, + 0x40579df2, + 0x40581e07, + 0x40589e2e, + 0x40591e5d, + 0x40599e8a, + 0x405a1e9e, + 0x405a9eae, + 0x405b1ec6, + 0x405b9ed7, + 0x405c1eea, + 0x405c9f0b, + 0x405d1f18, + 0x405d9f2f, + 0x405e1f6d, 0x405e8a95, - 0x405f1f38, - 0x405f9f45, - 0x40601f53, - 0x40609f75, - 0x40611f9d, - 0x40619fb2, - 0x40621fc9, - 0x40629fda, - 0x40631feb, - 0x4063a000, - 0x40642017, - 0x4064a043, - 0x4065205e, - 0x4065a075, - 0x4066208d, - 0x4066a0b7, - 0x406720e2, - 0x4067a103, - 0x40682116, - 0x4068a137, - 0x40692169, - 0x4069a197, - 0x406a21b8, - 0x406aa1d8, - 0x406b2360, - 0x406ba383, - 0x406c2399, - 0x406ca5c5, - 0x406d25f4, - 0x406da61c, - 0x406e264a, - 0x406ea662, - 0x406f2681, - 0x406fa696, - 0x407026a9, - 0x4070a6c6, + 0x405f1f8e, + 0x405f9f9b, + 0x40601fa9, + 0x40609fcb, + 0x4061200f, + 0x4061a047, + 0x4062205e, + 0x4062a06f, + 0x40632080, + 0x4063a095, + 0x406420ac, + 0x4064a0d8, + 0x406520f3, + 0x4065a10a, + 0x40662122, + 0x4066a14c, + 0x40672177, + 0x4067a198, + 0x406821ab, + 0x4068a1cc, + 0x406921fe, + 0x4069a22c, + 0x406a224d, + 0x406aa26d, + 0x406b23f5, + 0x406ba418, + 0x406c242e, + 0x406ca690, + 0x406d26bf, + 0x406da6e7, + 0x406e2715, + 0x406ea749, + 0x406f2768, + 0x406fa77d, + 0x40702790, + 0x4070a7ad, 0x40710800, - 0x4071a6d8, - 0x407226eb, - 0x4072a704, - 0x4073271c, + 0x4071a7bf, + 0x407227d2, + 0x4072a7eb, + 0x40732803, 0x4073936d, - 0x40742730, - 0x4074a74a, - 0x4075275b, - 0x4075a76f, - 0x4076277d, + 0x40742817, + 0x4074a831, + 0x40752842, + 0x4075a856, + 0x40762864, 0x407691aa, - 0x407727a2, - 0x4077a7c4, - 0x407827df, - 0x4078a818, - 0x4079282f, - 0x4079a845, - 0x407a2851, - 0x407aa864, - 0x407b2879, - 0x407ba88b, - 0x407c28a0, - 0x407ca8a9, - 0x407d2152, - 0x407d9c57, - 0x407e27f4, - 0x407e9e16, - 0x407f1a67, + 0x40772889, + 0x4077a8ab, + 0x407828c6, + 0x4078a8ff, + 0x40792916, + 0x4079a92c, + 0x407a2938, + 0x407aa94b, + 0x407b2960, + 0x407ba972, + 0x407c2987, + 0x407ca990, + 0x407d21e7, + 0x407d9c6e, + 0x407e28db, + 0x407e9e3e, + 0x407f1a7e, 0x407f9887, - 0x40801c2e, - 0x40809a8f, - 0x40811cd9, - 0x40819c08, - 0x40822635, + 0x40801c45, + 0x40809aa6, + 0x40811d01, + 0x40819c1f, + 0x40822700, 0x4082986d, - 0x40831df1, - 0x4083a028, - 0x40841aa3, - 0x40849e4e, - 0x41f4228b, - 0x41f9231d, - 0x41fe2210, - 0x41fea3ec, - 0x41ff24dd, - 0x420322a4, - 0x420822c6, - 0x4208a302, - 0x420921f4, - 0x4209a33c, - 0x420a224b, - 0x420aa22b, - 0x420b226b, - 0x420ba2e4, - 0x420c24f9, - 0x420ca3b9, - 0x420d23d3, - 0x420da40a, - 0x42122424, - 0x421724c0, - 0x4217a466, - 0x421c2488, - 0x421f2443, - 0x42212510, - 0x422624a3, - 0x422b25a9, - 0x422ba572, - 0x422c2591, - 0x422ca54c, - 0x422d252b, + 0x40831e19, + 0x4083a0bd, + 0x40841aba, + 0x40849e76, + 0x40851efb, + 0x40859ff3, + 0x40861f4f, + 0x40869c88, + 0x4087272d, + 0x4087a024, + 0x408818aa, + 0x41f42320, + 0x41f923b2, + 0x41fe22a5, + 0x41fea481, + 0x41ff2572, + 0x42032339, + 0x4208235b, + 0x4208a397, + 0x42092289, + 0x4209a3d1, + 0x420a22e0, + 0x420aa2c0, + 0x420b2300, + 0x420ba379, + 0x420c258e, + 0x420ca44e, + 0x420d2468, + 0x420da49f, + 0x421224b9, + 0x42172555, + 0x4217a4fb, + 0x421c251d, + 0x421f24d8, + 0x422125a5, + 0x42262538, + 0x422b2674, + 0x422ba622, + 0x422c265c, + 0x422ca5e1, + 0x422d25c0, + 0x422da641, + 0x422e2607, 0x4432072b, 0x4432873a, 0x44330746, @@ -793,69 +800,69 @@ Pod::Spec.new do |s| 0x4c3d136d, 0x4c3d937c, 0x4c3e1389, - 0x50322b22, - 0x5032ab31, - 0x50332b3c, - 0x5033ab4c, - 0x50342b65, - 0x5034ab7f, - 0x50352b8d, - 0x5035aba3, - 0x50362bb5, - 0x5036abcb, - 0x50372be4, - 0x5037abf7, - 0x50382c0f, - 0x5038ac20, - 0x50392c35, - 0x5039ac49, - 0x503a2c69, - 0x503aac7f, - 0x503b2c97, - 0x503baca9, - 0x503c2cc5, - 0x503cacdc, - 0x503d2cf5, - 0x503dad0b, - 0x503e2d18, - 0x503ead2e, - 0x503f2d40, + 0x50322c09, + 0x5032ac18, + 0x50332c23, + 0x5033ac33, + 0x50342c4c, + 0x5034ac66, + 0x50352c74, + 0x5035ac8a, + 0x50362c9c, + 0x5036acb2, + 0x50372ccb, + 0x5037acde, + 0x50382cf6, + 0x5038ad07, + 0x50392d1c, + 0x5039ad30, + 0x503a2d50, + 0x503aad66, + 0x503b2d7e, + 0x503bad90, + 0x503c2dac, + 0x503cadc3, + 0x503d2ddc, + 0x503dadf2, + 0x503e2dff, + 0x503eae15, + 0x503f2e27, 0x503f8382, - 0x50402d53, - 0x5040ad63, - 0x50412d7d, - 0x5041ad8c, - 0x50422da6, - 0x5042adc3, - 0x50432dd3, - 0x5043ade3, - 0x50442df2, + 0x50402e3a, + 0x5040ae4a, + 0x50412e64, + 0x5041ae73, + 0x50422e8d, + 0x5042aeaa, + 0x50432eba, + 0x5043aeca, + 0x50442ed9, 0x5044843f, - 0x50452e06, - 0x5045ae24, - 0x50462e37, - 0x5046ae4d, - 0x50472e5f, - 0x5047ae74, - 0x50482e9a, - 0x5048aea8, - 0x50492ebb, - 0x5049aed0, - 0x504a2ee6, - 0x504aaef6, - 0x504b2f16, - 0x504baf29, - 0x504c2f4c, - 0x504caf7a, - 0x504d2f8c, - 0x504dafa9, - 0x504e2fc4, - 0x504eafe0, - 0x504f2ff2, - 0x504fb009, - 0x50503018, + 0x50452eed, + 0x5045af0b, + 0x50462f1e, + 0x5046af34, + 0x50472f46, + 0x5047af5b, + 0x50482f81, + 0x5048af8f, + 0x50492fa2, + 0x5049afb7, + 0x504a2fcd, + 0x504aafdd, + 0x504b2ffd, + 0x504bb010, + 0x504c3033, + 0x504cb061, + 0x504d3073, + 0x504db090, + 0x504e30ab, + 0x504eb0c7, + 0x504f30d9, + 0x504fb0f0, + 0x505030ff, 0x505086ef, - 0x5051302b, + 0x50513112, 0x58320ec9, 0x68320e8b, 0x68328c25, @@ -1218,6 +1225,7 @@ Pod::Spec.new do |s| "BIO_NOT_SET\\0" "BLOCK_CIPHER_PAD_IS_WRONG\\0" "BUFFERED_MESSAGES_ON_CIPHER_CHANGE\\0" + "CANNOT_PARSE_LEAF_CERT\\0" "CA_DN_LENGTH_MISMATCH\\0" "CA_DN_TOO_LONG\\0" "CCS_RECEIVED_EARLY\\0" @@ -1261,6 +1269,7 @@ Pod::Spec.new do |s| "INVALID_COMPRESSION_LIST\\0" "INVALID_MESSAGE\\0" "INVALID_OUTER_RECORD_TYPE\\0" + "INVALID_SCT_LIST\\0" "INVALID_SSL_SESSION\\0" "INVALID_TICKET_KEYS_LENGTH\\0" "LENGTH_MISMATCH\\0" @@ -1290,15 +1299,19 @@ Pod::Spec.new do |s| "NO_RENEGOTIATION\\0" "NO_REQUIRED_DIGEST\\0" "NO_SHARED_CIPHER\\0" + "NO_SHARED_GROUP\\0" "NULL_SSL_CTX\\0" "NULL_SSL_METHOD_PASSED\\0" "OLD_SESSION_CIPHER_NOT_RETURNED\\0" + "OLD_SESSION_PRF_HASH_MISMATCH\\0" "OLD_SESSION_VERSION_NOT_RETURNED\\0" "PARSE_TLSEXT\\0" "PATH_TOO_LONG\\0" "PEER_DID_NOT_RETURN_A_CERTIFICATE\\0" "PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE\\0" + "PRE_SHARED_KEY_MUST_BE_LAST\\0" "PROTOCOL_IS_SHUTDOWN\\0" + "PSK_IDENTITY_BINDER_COUNT_MISMATCH\\0" "PSK_IDENTITY_NOT_FOUND\\0" "PSK_NO_CLIENT_CB\\0" "PSK_NO_SERVER_CB\\0" @@ -1350,7 +1363,9 @@ Pod::Spec.new do |s| "TLSV1_ALERT_USER_CANCELLED\\0" "TLSV1_BAD_CERTIFICATE_HASH_VALUE\\0" "TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE\\0" + "TLSV1_CERTIFICATE_REQUIRED\\0" "TLSV1_CERTIFICATE_UNOBTAINABLE\\0" + "TLSV1_UNKNOWN_PSK_IDENTITY\\0" "TLSV1_UNRECOGNIZED_NAME\\0" "TLSV1_UNSUPPORTED_EXTENSION\\0" "TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST\\0" @@ -1358,6 +1373,7 @@ Pod::Spec.new do |s| "TOO_MANY_EMPTY_FRAGMENTS\\0" "TOO_MANY_KEY_UPDATES\\0" "TOO_MANY_WARNING_ALERTS\\0" + "TOO_MUCH_SKIPPED_EARLY_DATA\\0" "UNABLE_TO_FIND_ECDH_PARAMETERS\\0" "UNEXPECTED_EXTENSION\\0" "UNEXPECTED_MESSAGE\\0" diff --git a/templates/gRPC-Core.podspec.template b/templates/gRPC-Core.podspec.template index 538e1e64905..1a9de243173 100644 --- a/templates/gRPC-Core.podspec.template +++ b/templates/gRPC-Core.podspec.template @@ -135,7 +135,7 @@ ss.header_mappings_dir = '.' ss.libraries = 'z' ss.dependency "#{s.name}/Interface", version - ss.dependency 'BoringSSL', '~> 8.0' + ss.dependency 'BoringSSL', '~> 9.0' ss.dependency 'nanopb', '~> 0.3' # To save you from scrolling, this is the last part of the podspec. From 8f2a054f1706fcda1d821b4c9dea250d0cb47d29 Mon Sep 17 00:00:00 2001 From: Michael Bausor Date: Wed, 12 Jul 2017 09:54:26 -0700 Subject: [PATCH 016/127] Support parameter to change PHP generated stub suffix --- src/compiler/php_generator.cc | 12 +++++++----- src/compiler/php_generator.h | 3 ++- src/compiler/php_generator_helpers.h | 17 +++++++++++++++-- src/compiler/php_plugin.cc | 5 +++-- 4 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/compiler/php_generator.cc b/src/compiler/php_generator.cc index 6d34761fdfd..38ec46e656e 100644 --- a/src/compiler/php_generator.cc +++ b/src/compiler/php_generator.cc @@ -97,13 +97,14 @@ void PrintMethod(const MethodDescriptor *method, Printer *out) { } // Prints out the service descriptor object -void PrintService(const ServiceDescriptor *service, Printer *out) { +void PrintService(const ServiceDescriptor *service, + const grpc::string ¶meter, Printer *out) { map vars; out->Print("/**\n"); out->Print(GetPHPComments(service, " *").c_str()); out->Print(" */\n"); - vars["name"] = service->name(); - out->Print(vars, "class $name$Client extends \\Grpc\\BaseStub {\n\n"); + vars["name"] = GetPHPServiceClassname(service, parameter); + out->Print(vars, "class $name$ extends \\Grpc\\BaseStub {\n\n"); out->Indent(); out->Indent(); out->Print( @@ -131,7 +132,8 @@ void PrintService(const ServiceDescriptor *service, Printer *out) { } grpc::string GenerateFile(const FileDescriptor *file, - const ServiceDescriptor *service) { + const ServiceDescriptor *service, + const grpc::string ¶meter) { grpc::string output; { StringOutputStream output_stream(&output); @@ -150,7 +152,7 @@ grpc::string GenerateFile(const FileDescriptor *file, vars["package"] = MessageIdentifierName(file->package()); out.Print(vars, "namespace $package$;\n\n"); - PrintService(service, &out); + PrintService(service, parameter, &out); } return output; } diff --git a/src/compiler/php_generator.h b/src/compiler/php_generator.h index 4518bc24f91..9a04bd33d70 100644 --- a/src/compiler/php_generator.h +++ b/src/compiler/php_generator.h @@ -24,7 +24,8 @@ namespace grpc_php_generator { grpc::string GenerateFile(const grpc::protobuf::FileDescriptor *file, - const grpc::protobuf::ServiceDescriptor *service); + const grpc::protobuf::ServiceDescriptor *service, + const grpc::string ¶meter); } // namespace grpc_php_generator diff --git a/src/compiler/php_generator_helpers.h b/src/compiler/php_generator_helpers.h index 3a5c08b3e69..5edebf6290a 100644 --- a/src/compiler/php_generator_helpers.h +++ b/src/compiler/php_generator_helpers.h @@ -26,9 +26,22 @@ namespace grpc_php_generator { +inline grpc::string GetPHPServiceClassname( + const grpc::protobuf::ServiceDescriptor *service, + const grpc::string ¶meter) { + grpc::string suffix; + if (parameter == "") { + suffix = "Client"; + } else { + suffix = parameter; + } + return service->name() + suffix; +} + inline grpc::string GetPHPServiceFilename( const grpc::protobuf::FileDescriptor *file, - const grpc::protobuf::ServiceDescriptor *service) { + const grpc::protobuf::ServiceDescriptor *service, + const grpc::string ¶meter) { std::vector tokens = grpc_generator::tokenize(file->package(), "."); std::ostringstream oss; @@ -36,7 +49,7 @@ inline grpc::string GetPHPServiceFilename( oss << (i == 0 ? "" : "/") << grpc_generator::CapitalizeFirstLetter(tokens[i]); } - return oss.str() + "/" + service->name() + "Client.php"; + return oss.str() + "/" + GetPHPServiceClassname(service, parameter) + ".php"; } // ReplaceAll replaces all instances of search with replace in s. diff --git a/src/compiler/php_plugin.cc b/src/compiler/php_plugin.cc index 7a581fd7bcb..bbe91656d5e 100644 --- a/src/compiler/php_plugin.cc +++ b/src/compiler/php_plugin.cc @@ -41,10 +41,11 @@ class PHPGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator { } for (int i = 0; i < file->service_count(); i++) { - grpc::string code = GenerateFile(file, file->service(i)); + grpc::string code = GenerateFile(file, file->service(i), parameter); // Get output file name - grpc::string file_name = GetPHPServiceFilename(file, file->service(i)); + grpc::string file_name = + GetPHPServiceFilename(file, file->service(i), parameter); std::unique_ptr output( context->Open(file_name)); From 68198b57442ac59cd9e18fdcbfe580c52f7faa62 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 12 Jul 2017 11:43:23 -0700 Subject: [PATCH 017/127] Transport layer recv (decompression) path --- .../chttp2/transport/chttp2_transport.c | 83 ++++++++++++++++--- .../transport/chttp2/transport/frame_data.c | 2 +- .../ext/transport/chttp2/transport/internal.h | 11 +++ 3 files changed, 83 insertions(+), 13 deletions(-) diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c index ab7dc3ba9ff..aea4ce4e287 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c @@ -668,6 +668,7 @@ static int init_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt, grpc_chttp2_incoming_metadata_buffer_init(&s->metadata_buffer[1], arena); grpc_chttp2_data_parser_init(&s->data_parser); grpc_slice_buffer_init(&s->flow_controlled_buffer); + grpc_slice_buffer_init(&s->decompressed_data_buffer); s->deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC); GRPC_CLOSURE_INIT(&s->complete_fetch_locked, complete_fetch_locked, s, grpc_schedule_on_exec_ctx); @@ -706,6 +707,7 @@ static void destroy_stream_locked(grpc_exec_ctx *exec_ctx, void *sp, grpc_slice_buffer_destroy_internal(exec_ctx, &s->unprocessed_incoming_frames_buffer); grpc_slice_buffer_destroy_internal(exec_ctx, &s->frame_storage); + grpc_slice_buffer_destroy_internal(exec_ctx, &s->decompressed_data_buffer); grpc_chttp2_list_remove_stalled_by_transport(t, s); grpc_chttp2_list_remove_stalled_by_stream(t, s); @@ -756,6 +758,11 @@ static void destroy_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt, grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt; grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs; + if (s->stream_decompression_ctx != NULL) { + grpc_stream_compression_context_destroy(s->stream_decompression_ctx); + s->stream_decompression_ctx = NULL; + } + s->destroy_stream_arg = then_schedule_closure; GRPC_CLOSURE_SCHED( exec_ctx, GRPC_CLOSURE_INIT(&s->destroy_stream, destroy_stream_locked, s, @@ -1430,12 +1437,7 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op, s->recv_message_ready = op_payload->recv_message.recv_message_ready; s->recv_message = op_payload->recv_message.recv_message; if (s->id != 0) { - if (s->pending_byte_stream) { - already_received = s->frame_storage.length; - } else { - already_received = s->frame_storage.length + - s->unprocessed_incoming_frames_buffer.length; - } + already_received = s->frame_storage.length; incoming_byte_stream_update_flow_control(exec_ctx, t, s, 5, already_received); } @@ -1659,10 +1661,42 @@ void grpc_chttp2_maybe_complete_recv_message(grpc_exec_ctx *exec_ctx, if (s->unprocessed_incoming_frames_buffer.length == 0) { grpc_slice_buffer_swap(&s->unprocessed_incoming_frames_buffer, &s->frame_storage); + s->unprocessed_incoming_frames_decompressed = false; + } + if (s->stream_compression_recv_enabled && + !s->unprocessed_incoming_frames_decompressed) { + grpc_slice_buffer decompressed_data; + bool end_of_context; + grpc_slice_buffer_init(&decompressed_data); + if (!s->stream_decompression_ctx) { + s->stream_decompression_ctx = + grpc_stream_compression_context_create( + GRPC_STREAM_COMPRESSION_DECOMPRESS); + } + if (!grpc_stream_decompress(s->stream_decompression_ctx, + &s->unprocessed_incoming_frames_buffer, + &decompressed_data, NULL, 5, + &end_of_context)) { + grpc_slice_buffer_reset_and_unref_internal(exec_ctx, + &s->frame_storage); + grpc_slice_buffer_reset_and_unref_internal( + exec_ctx, &s->unprocessed_incoming_frames_buffer); + s->seen_error = true; + } else { + error = grpc_deframe_unprocessed_incoming_frames( + exec_ctx, &s->data_parser, s, &decompressed_data, NULL, + s->recv_message); + if (end_of_context) { + grpc_stream_compression_context_destroy( + s->stream_decompression_ctx); + s->stream_decompression_ctx = NULL; + } + } + } else { + error = grpc_deframe_unprocessed_incoming_frames( + exec_ctx, &s->data_parser, s, + &s->unprocessed_incoming_frames_buffer, NULL, s->recv_message); } - error = grpc_deframe_unprocessed_incoming_frames( - exec_ctx, &s->data_parser, s, - &s->unprocessed_incoming_frames_buffer, NULL, s->recv_message); if (error != GRPC_ERROR_NONE) { s->seen_error = true; grpc_slice_buffer_reset_and_unref_internal(exec_ctx, @@ -2568,6 +2602,7 @@ static void incoming_byte_stream_next_locked(grpc_exec_ctx *exec_ctx, if (s->frame_storage.length > 0) { grpc_slice_buffer_swap(&s->frame_storage, &s->unprocessed_incoming_frames_buffer); + s->unprocessed_incoming_frames_decompressed = false; GRPC_CLOSURE_SCHED(exec_ctx, bs->next_action.on_complete, GRPC_ERROR_NONE); } else if (s->byte_stream_error != GRPC_ERROR_NONE) { GRPC_CLOSURE_SCHED(exec_ctx, bs->next_action.on_complete, @@ -2629,17 +2664,41 @@ static grpc_error *incoming_byte_stream_pull(grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs = (grpc_chttp2_incoming_byte_stream *)byte_stream; grpc_chttp2_stream *s = bs->stream; + grpc_error *error; if (s->unprocessed_incoming_frames_buffer.length > 0) { - grpc_error *error = grpc_deframe_unprocessed_incoming_frames( + if (s->stream_compression_recv_enabled && + !s->unprocessed_incoming_frames_decompressed) { + bool end_of_context; + if (!s->stream_decompression_ctx) { + s->stream_decompression_ctx = grpc_stream_compression_context_create( + GRPC_STREAM_COMPRESSION_DECOMPRESS); + } + if (!grpc_stream_decompress(s->stream_decompression_ctx, + &s->unprocessed_incoming_frames_buffer, + &s->decompressed_data_buffer, NULL, + ~(size_t)0, &end_of_context)) { + error = + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Stream decompression error."); + return error; + } + GPR_ASSERT(s->unprocessed_incoming_frames_buffer.length == 0); + grpc_slice_buffer_swap(&s->unprocessed_incoming_frames_buffer, + &s->decompressed_data_buffer); + s->unprocessed_incoming_frames_decompressed = true; + if (end_of_context) { + grpc_stream_compression_context_destroy(s->stream_decompression_ctx); + s->stream_decompression_ctx = NULL; + } + } + error = grpc_deframe_unprocessed_incoming_frames( exec_ctx, &s->data_parser, s, &s->unprocessed_incoming_frames_buffer, slice, NULL); if (error != GRPC_ERROR_NONE) { return error; } } else { - grpc_error *error = - GRPC_ERROR_CREATE_FROM_STATIC_STRING("Truncated message"); + error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Truncated message"); GRPC_CLOSURE_SCHED(exec_ctx, &s->reset_byte_stream, GRPC_ERROR_REF(error)); return error; } diff --git a/src/core/ext/transport/chttp2/transport/frame_data.c b/src/core/ext/transport/chttp2/transport/frame_data.c index dead6be77f5..222d2177b29 100644 --- a/src/core/ext/transport/chttp2/transport/frame_data.c +++ b/src/core/ext/transport/chttp2/transport/frame_data.c @@ -293,7 +293,6 @@ grpc_error *grpc_chttp2_data_parser_parse(grpc_exec_ctx *exec_ctx, void *parser, grpc_chttp2_transport *t, grpc_chttp2_stream *s, grpc_slice slice, int is_last) { - /* grpc_error *error = parse_inner_buffer(exec_ctx, p, t, s, slice); */ if (!s->pending_byte_stream) { grpc_slice_ref_internal(slice); grpc_slice_buffer_add(&s->frame_storage, slice); @@ -304,6 +303,7 @@ grpc_error *grpc_chttp2_data_parser_parse(grpc_exec_ctx *exec_ctx, void *parser, grpc_slice_buffer_add(&s->unprocessed_incoming_frames_buffer, slice); GRPC_CLOSURE_SCHED(exec_ctx, s->on_next, GRPC_ERROR_NONE); s->on_next = NULL; + s->unprocessed_incoming_frames_decompressed = false; } else { grpc_slice_ref_internal(slice); grpc_slice_buffer_add(&s->frame_storage, slice); diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h index b0726fdb5fd..64196d8c1c6 100644 --- a/src/core/ext/transport/chttp2/transport/internal.h +++ b/src/core/ext/transport/chttp2/transport/internal.h @@ -519,6 +519,17 @@ struct grpc_chttp2_stream { grpc_chttp2_write_cb *on_write_finished_cbs; grpc_chttp2_write_cb *finish_after_write; size_t sending_bytes; + + /** Whether stream compression send is enabled or not */ + bool stream_compression_recv_enabled; + /** Whether bytes stored in unprocessed_incoming_byte_stream is decompressed + */ + bool unprocessed_incoming_frames_decompressed; + /** Stream compression decompress context */ + grpc_stream_compression_context *stream_decompression_ctx; + + /** Temporary buffer storing decompressed data */ + grpc_slice_buffer decompressed_data_buffer; }; /** Transport writing call flow: From e89c83a21bf2975e6c686e5dc11fc5d17a22d590 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 12 Jul 2017 11:49:27 -0700 Subject: [PATCH 018/127] Transport layer send (compression) path --- .../chttp2/transport/chttp2_transport.c | 6 ++ .../ext/transport/chttp2/transport/internal.h | 11 ++- .../ext/transport/chttp2/transport/writing.c | 82 ++++++++++++++----- 3 files changed, 79 insertions(+), 20 deletions(-) diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c index aea4ce4e287..00b0738b20d 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c @@ -668,6 +668,7 @@ static int init_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt, grpc_chttp2_incoming_metadata_buffer_init(&s->metadata_buffer[1], arena); grpc_chttp2_data_parser_init(&s->data_parser); grpc_slice_buffer_init(&s->flow_controlled_buffer); + grpc_slice_buffer_init(&s->compressed_data_buffer); grpc_slice_buffer_init(&s->decompressed_data_buffer); s->deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC); GRPC_CLOSURE_INIT(&s->complete_fetch_locked, complete_fetch_locked, s, @@ -707,6 +708,7 @@ static void destroy_stream_locked(grpc_exec_ctx *exec_ctx, void *sp, grpc_slice_buffer_destroy_internal(exec_ctx, &s->unprocessed_incoming_frames_buffer); grpc_slice_buffer_destroy_internal(exec_ctx, &s->frame_storage); + grpc_slice_buffer_destroy_internal(exec_ctx, &s->compressed_data_buffer); grpc_slice_buffer_destroy_internal(exec_ctx, &s->decompressed_data_buffer); grpc_chttp2_list_remove_stalled_by_transport(t, s); @@ -758,6 +760,10 @@ static void destroy_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt, grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt; grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs; + if (s->stream_compression_ctx != NULL) { + grpc_stream_compression_context_destroy(s->stream_compression_ctx); + s->stream_compression_ctx = NULL; + } if (s->stream_decompression_ctx != NULL) { grpc_stream_compression_context_destroy(s->stream_decompression_ctx); s->stream_decompression_ctx = NULL; diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h index 64196d8c1c6..0f29b10d377 100644 --- a/src/core/ext/transport/chttp2/transport/internal.h +++ b/src/core/ext/transport/chttp2/transport/internal.h @@ -522,12 +522,21 @@ struct grpc_chttp2_stream { /** Whether stream compression send is enabled or not */ bool stream_compression_recv_enabled; + /** Whether stream compression recv is enabled or not */ + bool stream_compression_send_enabled; /** Whether bytes stored in unprocessed_incoming_byte_stream is decompressed */ bool unprocessed_incoming_frames_decompressed; /** Stream compression decompress context */ grpc_stream_compression_context *stream_decompression_ctx; - + /** Stream compression compress context */ + grpc_stream_compression_context *stream_compression_ctx; + + /** Buffer storing data that is compressed but not sent */ + grpc_slice_buffer compressed_data_buffer; + /** Amount of uncompressed bytes sent out when compressed_data_buffer is + * emptied */ + size_t uncompressed_data_size; /** Temporary buffer storing decompressed data */ grpc_slice_buffer decompressed_data_buffer; }; diff --git a/src/core/ext/transport/chttp2/transport/writing.c b/src/core/ext/transport/chttp2/transport/writing.c index 315f2a67a21..d7221eaf30a 100644 --- a/src/core/ext/transport/chttp2/transport/writing.c +++ b/src/core/ext/transport/chttp2/transport/writing.c @@ -303,7 +303,8 @@ grpc_chttp2_begin_write_result grpc_chttp2_begin_write( } if (sent_initial_metadata) { /* send any body bytes, if allowed by flow control */ - if (s->flow_controlled_buffer.length > 0) { + if (s->flow_controlled_buffer.length > 0 || + s->compressed_data_buffer.length > 0) { uint32_t stream_outgoing_window = (uint32_t)GPR_MAX( 0, s->outgoing_window_delta + @@ -314,21 +315,63 @@ grpc_chttp2_begin_write_result grpc_chttp2_begin_write( [GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE], GPR_MIN(stream_outgoing_window, t->outgoing_window)); if (max_outgoing > 0) { - uint32_t send_bytes = - (uint32_t)GPR_MIN(max_outgoing, s->flow_controlled_buffer.length); - bool is_last_data_frame = - s->fetching_send_message == NULL && - send_bytes == s->flow_controlled_buffer.length; - bool is_last_frame = - is_last_data_frame && s->send_trailing_metadata != NULL && - grpc_metadata_batch_is_empty(s->send_trailing_metadata); - grpc_chttp2_encode_data(s->id, &s->flow_controlled_buffer, send_bytes, - is_last_frame, &s->stats.outgoing, - &t->outbuf); - GRPC_CHTTP2_FLOW_DEBIT_STREAM("write", t, s, outgoing_window_delta, - send_bytes); - GRPC_CHTTP2_FLOW_DEBIT_TRANSPORT("write", t, outgoing_window, - send_bytes); + bool is_last_data_frame; + bool is_last_frame; + if (s->stream_compression_send_enabled) { + while ((s->flow_controlled_buffer.length > 0 || + s->compressed_data_buffer.length > 0) && + max_outgoing > 0) { + if (s->compressed_data_buffer.length > 0) { + uint32_t send_bytes = (uint32_t)GPR_MIN( + max_outgoing, s->compressed_data_buffer.length); + is_last_data_frame = + (send_bytes == s->compressed_data_buffer.length && + s->flow_controlled_buffer.length == 0 && + s->fetching_send_message == NULL); + is_last_frame = + is_last_data_frame && s->send_trailing_metadata != NULL && + grpc_metadata_batch_is_empty(s->send_trailing_metadata); + grpc_chttp2_encode_data(s->id, &s->compressed_data_buffer, + send_bytes, is_last_frame, + &s->stats.outgoing, &t->outbuf); + GRPC_CHTTP2_FLOW_DEBIT_STREAM( + "write", t, s, outgoing_window_delta, send_bytes); + GRPC_CHTTP2_FLOW_DEBIT_TRANSPORT("write", t, outgoing_window, + send_bytes); + max_outgoing -= send_bytes; + if (s->compressed_data_buffer.length == 0) { + s->sending_bytes += s->uncompressed_data_size; + } + } else { + if (s->stream_compression_ctx == NULL) { + s->stream_compression_ctx = + grpc_stream_compression_context_create( + GRPC_STREAM_COMPRESSION_COMPRESS); + } + s->uncompressed_data_size = s->flow_controlled_buffer.length; + GPR_ASSERT(grpc_stream_compress( + s->stream_compression_ctx, &s->flow_controlled_buffer, + &s->compressed_data_buffer, NULL, ~(size_t)0, + GRPC_STREAM_COMPRESSION_FLUSH_SYNC)); + } + } + } else { + uint32_t send_bytes = (uint32_t)GPR_MIN( + max_outgoing, s->flow_controlled_buffer.length); + is_last_data_frame = s->fetching_send_message == NULL && + send_bytes == s->flow_controlled_buffer.length; + is_last_frame = + is_last_data_frame && s->send_trailing_metadata != NULL && + grpc_metadata_batch_is_empty(s->send_trailing_metadata); + grpc_chttp2_encode_data(s->id, &s->flow_controlled_buffer, + send_bytes, is_last_frame, + &s->stats.outgoing, &t->outbuf); + GRPC_CHTTP2_FLOW_DEBIT_STREAM("write", t, s, outgoing_window_delta, + send_bytes); + GRPC_CHTTP2_FLOW_DEBIT_TRANSPORT("write", t, outgoing_window, + send_bytes); + s->sending_bytes += send_bytes; + } t->ping_state.pings_before_data_required = t->ping_policy.max_pings_without_data; if (!t->is_client) { @@ -345,9 +388,9 @@ grpc_chttp2_begin_write_result grpc_chttp2_begin_write( &s->stats.outgoing)); } } - s->sending_bytes += send_bytes; now_writing = true; - if (s->flow_controlled_buffer.length > 0) { + if (s->flow_controlled_buffer.length > 0 || + s->compressed_data_buffer.length > 0) { GRPC_CHTTP2_STREAM_REF(s, "chttp2_writing:fork"); grpc_chttp2_list_add_writable_stream(t, s); } @@ -361,7 +404,8 @@ grpc_chttp2_begin_write_result grpc_chttp2_begin_write( } if (s->send_trailing_metadata != NULL && s->fetching_send_message == NULL && - s->flow_controlled_buffer.length == 0) { + s->flow_controlled_buffer.length == 0 && + s->compressed_data_buffer.length == 0) { GRPC_CHTTP2_IF_TRACING(gpr_log(GPR_INFO, "sending trailing_metadata")); if (grpc_metadata_batch_is_empty(s->send_trailing_metadata)) { grpc_chttp2_encode_data(s->id, &s->flow_controlled_buffer, 0, true, From abe3cf51f02d48b28fd67d78e7a3060d763148b5 Mon Sep 17 00:00:00 2001 From: Guantao Liu Date: Wed, 12 Jul 2017 17:36:30 -0700 Subject: [PATCH 019/127] Add a new metric 'Queries/CPU-sec'. Enable internal credential types. --- src/proto/grpc/testing/control.proto | 5 ++++ test/cpp/qps/BUILD | 2 ++ test/cpp/qps/client.h | 14 ++++++++-- test/cpp/qps/driver.cc | 36 ++++++++++++++++++++----- test/cpp/qps/driver.h | 5 ++-- test/cpp/qps/qps_json_driver.cc | 12 ++++++--- test/cpp/qps/qps_worker.cc | 8 ++++-- test/cpp/qps/qps_worker.h | 3 ++- test/cpp/qps/report.cc | 21 +++++++++++++++ test/cpp/qps/report.h | 7 +++++ test/cpp/qps/server.h | 15 ++++++----- test/cpp/qps/worker.cc | 5 +++- test/cpp/util/create_test_channel.cc | 40 +++++++++++++++++++++------- test/cpp/util/create_test_channel.h | 6 +++++ 14 files changed, 146 insertions(+), 33 deletions(-) diff --git a/src/proto/grpc/testing/control.proto b/src/proto/grpc/testing/control.proto index 48016642f74..2ff2e4e8a28 100644 --- a/src/proto/grpc/testing/control.proto +++ b/src/proto/grpc/testing/control.proto @@ -64,6 +64,7 @@ message LoadParams { message SecurityParams { bool use_test_ca = 1; string server_host_override = 2; + string cred_type = 3; } message ChannelArg { @@ -240,6 +241,10 @@ message ScenarioResultSummary // Number of polls called inside completion queue per request double client_polls_per_request = 15; double server_polls_per_request = 16; + + // Queries per CPU-sec over all servers or clients + double server_queries_per_cpu_sec = 17; + double client_queries_per_cpu_sec = 18; } // Results of a single benchmark scenario. diff --git a/test/cpp/qps/BUILD b/test/cpp/qps/BUILD index 4d8b3b40e3c..a3f70cf8b5b 100644 --- a/test/cpp/qps/BUILD +++ b/test/cpp/qps/BUILD @@ -77,6 +77,7 @@ grpc_cc_library( "//src/proto/grpc/testing:services_proto", "//test/core/util:gpr_test_util", "//test/core/util:grpc_test_util", + "//test/cpp/util:test_util", ], ) @@ -141,6 +142,7 @@ grpc_cc_binary( ":benchmark_config", ":driver_impl", "//:grpc++", + "//test/cpp/util:test_config", ], external_deps = [ "gflags", diff --git a/test/cpp/qps/client.h b/test/cpp/qps/client.h index e759446c1ae..f47f378a984 100644 --- a/test/cpp/qps/client.h +++ b/test/cpp/qps/client.h @@ -39,6 +39,7 @@ #include "test/cpp/qps/interarrival.h" #include "test/cpp/qps/usage_timer.h" #include "test/cpp/util/create_test_channel.h" +#include "test/cpp/util/test_credentials_provider.h" namespace grpc { namespace testing { @@ -407,9 +408,18 @@ class ClientImpl : public Client { ChannelArguments args; args.SetInt("shard_to_ensure_no_subchannel_merges", shard); set_channel_args(config, &args); + + grpc::string type; + if (config.has_security_params() && + config.security_params().cred_type().empty()) { + type = kTlsCredentialsType; + } else { + type = config.security_params().cred_type(); + } + channel_ = CreateTestChannel( - target, config.security_params().server_host_override(), - config.has_security_params(), !config.security_params().use_test_ca(), + target, type, config.security_params().server_host_override(), + !config.security_params().use_test_ca(), std::shared_ptr(), args); gpr_log(GPR_INFO, "Connecting to %s", target.c_str()); GPR_ASSERT(channel_->WaitForConnected( diff --git a/test/cpp/qps/driver.cc b/test/cpp/qps/driver.cc index fbd8d1b1e76..bb4e7536e84 100644 --- a/test/cpp/qps/driver.cc +++ b/test/cpp/qps/driver.cc @@ -40,6 +40,7 @@ #include "test/cpp/qps/histogram.h" #include "test/cpp/qps/qps_worker.h" #include "test/cpp/qps/stats.h" +#include "test/cpp/util/test_credentials_provider.h" using std::list; using std::thread; @@ -172,13 +173,27 @@ static void postprocess_scenario_result(ScenarioResult* result) { sum(result->client_stats(), CliPollCount) / histogram.Count()); result->mutable_summary()->set_server_polls_per_request( sum(result->server_stats(), SvrPollCount) / histogram.Count()); + + auto server_queries_per_cpu_sec = + histogram.Count() / + (sum(result->server_stats(), ServerSystemTime) + + sum(result->server_stats(), ServerUserTime)); + auto client_queries_per_cpu_sec = + histogram.Count() / + (sum(result->client_stats(), SystemTime) + + sum(result->client_stats(), UserTime)); + + result->mutable_summary()->set_server_queries_per_cpu_sec( + server_queries_per_cpu_sec); + result->mutable_summary()->set_client_queries_per_cpu_sec( + client_queries_per_cpu_sec); } std::unique_ptr RunScenario( const ClientConfig& initial_client_config, size_t num_clients, const ServerConfig& initial_server_config, size_t num_servers, int warmup_seconds, int benchmark_seconds, int spawn_local_worker_count, - const char* qps_server_target_override) { + const char* qps_server_target_override, const char* credential_type) { // Log everything from the driver gpr_set_log_verbosity(GPR_LOG_SEVERITY_DEBUG); @@ -214,7 +229,7 @@ std::unique_ptr RunScenario( } int driver_port = grpc_pick_unused_port_or_die(); - local_workers.emplace_back(new QpsWorker(driver_port)); + local_workers.emplace_back(new QpsWorker(driver_port, 0, credential_type)); char addr[256]; sprintf(addr, "localhost:%d", driver_port); if (spawn_local_worker_count < 0) { @@ -246,12 +261,15 @@ std::unique_ptr RunScenario( }; std::vector servers(num_servers); std::unordered_map> hosts_cores; + ChannelArguments channel_args; for (size_t i = 0; i < num_servers; i++) { gpr_log(GPR_INFO, "Starting server on %s (worker #%" PRIuPTR ")", workers[i].c_str(), i); servers[i].stub = WorkerService::NewStub( - CreateChannel(workers[i], InsecureChannelCredentials())); + CreateChannel(workers[i], + GetCredentialsProvider()->GetChannelCredentials( + credential_type, &channel_args))); ServerConfig server_config = initial_server_config; if (server_config.core_limit() != 0) { @@ -298,7 +316,9 @@ std::unique_ptr RunScenario( gpr_log(GPR_INFO, "Starting client on %s (worker #%" PRIuPTR ")", worker.c_str(), i + num_servers); clients[i].stub = WorkerService::NewStub( - CreateChannel(worker, InsecureChannelCredentials())); + CreateChannel(worker, + GetCredentialsProvider()->GetChannelCredentials( + credential_type, &channel_args))); ClientConfig per_client_config = client_config; if (initial_client_config.core_limit() != 0) { @@ -483,16 +503,20 @@ std::unique_ptr RunScenario( return result; } -bool RunQuit() { +bool RunQuit(const char* credential_type) { // Get client, server lists bool result = true; auto workers = get_workers("QPS_WORKERS"); if (workers.size() == 0) { return false; } + + ChannelArguments channel_args; for (size_t i = 0; i < workers.size(); i++) { auto stub = WorkerService::NewStub( - CreateChannel(workers[i], InsecureChannelCredentials())); + CreateChannel(workers[i], + GetCredentialsProvider()->GetChannelCredentials( + credential_type, &channel_args))); Void dummy; grpc::ClientContext ctx; ctx.set_wait_for_ready(true); diff --git a/test/cpp/qps/driver.h b/test/cpp/qps/driver.h index def32c6f0ef..ddf75ce5872 100644 --- a/test/cpp/qps/driver.h +++ b/test/cpp/qps/driver.h @@ -31,9 +31,10 @@ std::unique_ptr RunScenario( const grpc::testing::ClientConfig& client_config, size_t num_clients, const grpc::testing::ServerConfig& server_config, size_t num_servers, int warmup_seconds, int benchmark_seconds, int spawn_local_worker_count, - const char* qps_server_target_override = ""); + const char* qps_server_target_override = "", + const char* credential_type = "INSECURE_CREDENTIALS"); -bool RunQuit(); +bool RunQuit(const char* credential_type = "INSECURE_CREDENTIALS"); } // namespace testing } // namespace grpc diff --git a/test/cpp/qps/qps_json_driver.cc b/test/cpp/qps/qps_json_driver.cc index 590c22ec29f..d4698a7dc2f 100644 --- a/test/cpp/qps/qps_json_driver.cc +++ b/test/cpp/qps/qps_json_driver.cc @@ -30,6 +30,7 @@ #include "test/cpp/qps/driver.h" #include "test/cpp/qps/parse_json.h" #include "test/cpp/qps/report.h" +#include "test/cpp/util/test_config.h" DEFINE_string(scenarios_file, "", "JSON file containing an array of Scenario objects"); @@ -60,6 +61,9 @@ DEFINE_string(qps_server_target_override, "", DEFINE_string(json_file_out, "", "File to write the JSON output to."); +DEFINE_string(credential_type, "INSECURE_CREDENTIALS", + "Credential type for communication with workers"); + namespace grpc { namespace testing { @@ -71,7 +75,8 @@ static std::unique_ptr RunAndReport(const Scenario& scenario, scenario.server_config(), scenario.num_servers(), scenario.warmup_seconds(), scenario.benchmark_seconds(), scenario.spawn_local_worker_count(), - FLAGS_qps_server_target_override.c_str()); + FLAGS_qps_server_target_override.c_str(), + FLAGS_credential_type.c_str()); // Amend the result with scenario config. Eventually we should adjust // RunScenario contract so we don't need to touch the result here. @@ -83,6 +88,7 @@ static std::unique_ptr RunAndReport(const Scenario& scenario, GetReporter()->ReportTimes(*result); GetReporter()->ReportCpuUsage(*result); GetReporter()->ReportPollCount(*result); + GetReporter()->ReportQueriesPerCpuSec(*result); for (int i = 0; *success && i < result->client_success_size(); i++) { *success = result->client_success(i); @@ -184,7 +190,7 @@ static bool QpsDriver() { } else if (scjson) { json = FLAGS_scenarios_json.c_str(); } else if (FLAGS_quit) { - return RunQuit(); + return RunQuit(FLAGS_credential_type.c_str()); } // Parse into an array of scenarios @@ -219,7 +225,7 @@ static bool QpsDriver() { } // namespace grpc int main(int argc, char** argv) { - grpc::testing::InitBenchmark(&argc, &argv, true); + grpc::testing::InitTest(&argc, &argv, true); bool ok = grpc::testing::QpsDriver(); diff --git a/test/cpp/qps/qps_worker.cc b/test/cpp/qps/qps_worker.cc index 10bc5422e13..4db4c868241 100644 --- a/test/cpp/qps/qps_worker.cc +++ b/test/cpp/qps/qps_worker.cc @@ -41,6 +41,7 @@ #include "test/cpp/qps/client.h" #include "test/cpp/qps/server.h" #include "test/cpp/util/create_test_channel.h" +#include "test/cpp/util/test_credentials_provider.h" namespace grpc { namespace testing { @@ -263,7 +264,8 @@ class WorkerServiceImpl final : public WorkerService::Service { QpsWorker* worker_; }; -QpsWorker::QpsWorker(int driver_port, int server_port) { +QpsWorker::QpsWorker(int driver_port, int server_port, + const char* credential_type) { impl_.reset(new WorkerServiceImpl(server_port, this)); gpr_atm_rel_store(&done_, static_cast(0)); @@ -271,7 +273,9 @@ QpsWorker::QpsWorker(int driver_port, int server_port) { gpr_join_host_port(&server_address, "::", driver_port); ServerBuilder builder; - builder.AddListeningPort(server_address, InsecureServerCredentials()); + builder.AddListeningPort(server_address, + GetCredentialsProvider()->GetServerCredentials( + credential_type)); builder.RegisterService(impl_.get()); gpr_free(server_address); diff --git a/test/cpp/qps/qps_worker.h b/test/cpp/qps/qps_worker.h index c8a7be93605..ab5e26a10e4 100644 --- a/test/cpp/qps/qps_worker.h +++ b/test/cpp/qps/qps_worker.h @@ -33,7 +33,8 @@ class WorkerServiceImpl; class QpsWorker { public: - explicit QpsWorker(int driver_port, int server_port = 0); + explicit QpsWorker(int driver_port, int server_port = 0, + const char* credential_type = "INSECURE_CREDENTIALS"); ~QpsWorker(); bool Done() const; diff --git a/test/cpp/qps/report.cc b/test/cpp/qps/report.cc index 809c5630442..a45b10bcb81 100644 --- a/test/cpp/qps/report.cc +++ b/test/cpp/qps/report.cc @@ -71,6 +71,12 @@ void CompositeReporter::ReportPollCount(const ScenarioResult& result) { } } +void CompositeReporter::ReportQueriesPerCpuSec(const ScenarioResult& result) { + for (size_t i = 0; i < reporters_.size(); ++i) { + reporters_[i]->ReportQueriesPerCpuSec(result); + } +} + void GprLogReporter::ReportQPS(const ScenarioResult& result) { gpr_log(GPR_INFO, "QPS: %.1f", result.summary().qps()); if (result.summary().failed_requests_per_second() > 0) { @@ -119,6 +125,13 @@ void GprLogReporter::ReportPollCount(const ScenarioResult& result) { result.summary().server_polls_per_request()); } +void GprLogReporter::ReportQueriesPerCpuSec(const ScenarioResult& result) { + gpr_log(GPR_INFO, "Server Queries/CPU-sec: %.2f", + result.summary().server_queries_per_cpu_sec()); + gpr_log(GPR_INFO, "Client Queries/CPU-sec: %.2f", + result.summary().client_queries_per_cpu_sec()); +} + void JsonReporter::ReportQPS(const ScenarioResult& result) { grpc::string json_string = SerializeJson(result, "type.googleapis.com/grpc.testing.ScenarioResult"); @@ -147,6 +160,10 @@ void JsonReporter::ReportPollCount(const ScenarioResult& result) { // NOP - all reporting is handled by ReportQPS. } +void JsonReporter::ReportQueriesPerCpuSec(const ScenarioResult& result) { + // NOP - all reporting is handled by ReportQPS. +} + void RpcReporter::ReportQPS(const ScenarioResult& result) { grpc::ClientContext context; grpc::Status status; @@ -183,5 +200,9 @@ void RpcReporter::ReportPollCount(const ScenarioResult& result) { // NOP - all reporting is handled by ReportQPS. } +void RpcReporter::ReportQueriesPerCpuSec(const ScenarioResult& result) { + // NOP - all reporting is handled by ReportQPS. +} + } // namespace testing } // namespace grpc diff --git a/test/cpp/qps/report.h b/test/cpp/qps/report.h index 0bd398fd2a2..321be2a97fa 100644 --- a/test/cpp/qps/report.h +++ b/test/cpp/qps/report.h @@ -64,6 +64,9 @@ class Reporter { /** Reports client and server poll usage inside completion queue. */ virtual void ReportPollCount(const ScenarioResult& result) = 0; + /** Reports queries per cpu-sec. */ + virtual void ReportQueriesPerCpuSec(const ScenarioResult& result) = 0; + private: const string name_; }; @@ -82,6 +85,7 @@ class CompositeReporter : public Reporter { void ReportTimes(const ScenarioResult& result) override; void ReportCpuUsage(const ScenarioResult& result) override; void ReportPollCount(const ScenarioResult& result) override; + void ReportQueriesPerCpuSec(const ScenarioResult& result) override; private: std::vector > reporters_; @@ -99,6 +103,7 @@ class GprLogReporter : public Reporter { void ReportTimes(const ScenarioResult& result) override; void ReportCpuUsage(const ScenarioResult& result) override; void ReportPollCount(const ScenarioResult& result) override; + void ReportQueriesPerCpuSec(const ScenarioResult& result) override; }; /** Dumps the report to a JSON file. */ @@ -114,6 +119,7 @@ class JsonReporter : public Reporter { void ReportTimes(const ScenarioResult& result) override; void ReportCpuUsage(const ScenarioResult& result) override; void ReportPollCount(const ScenarioResult& result) override; + void ReportQueriesPerCpuSec(const ScenarioResult& result) override; const string report_file_; }; @@ -130,6 +136,7 @@ class RpcReporter : public Reporter { void ReportTimes(const ScenarioResult& result) override; void ReportCpuUsage(const ScenarioResult& result) override; void ReportPollCount(const ScenarioResult& result) override; + void ReportQueriesPerCpuSec(const ScenarioResult& result) override; std::unique_ptr stub_; }; diff --git a/test/cpp/qps/server.h b/test/cpp/qps/server.h index 4b699e07080..c0dac96d8b8 100644 --- a/test/cpp/qps/server.h +++ b/test/cpp/qps/server.h @@ -32,6 +32,7 @@ #include "test/core/end2end/data/ssl_test_data.h" #include "test/core/util/port.h" #include "test/cpp/qps/usage_timer.h" +#include "test/cpp/util/test_credentials_provider.h" namespace grpc { namespace testing { @@ -89,12 +90,14 @@ class Server { static std::shared_ptr CreateServerCredentials( const ServerConfig& config) { if (config.has_security_params()) { - SslServerCredentialsOptions::PemKeyCertPair pkcp = {test_server1_key, - test_server1_cert}; - SslServerCredentialsOptions ssl_opts; - ssl_opts.pem_root_certs = ""; - ssl_opts.pem_key_cert_pairs.push_back(pkcp); - return SslServerCredentials(ssl_opts); + grpc::string type; + if (config.security_params().cred_type().empty()) { + type = kTlsCredentialsType; + } else { + type = config.security_params().cred_type(); + } + + return GetCredentialsProvider()->GetServerCredentials(type); } else { return InsecureServerCredentials(); } diff --git a/test/cpp/qps/worker.cc b/test/cpp/qps/worker.cc index fd51d32db0d..7a8036327f6 100644 --- a/test/cpp/qps/worker.cc +++ b/test/cpp/qps/worker.cc @@ -30,6 +30,8 @@ DEFINE_int32(driver_port, 0, "Port for communication with driver"); DEFINE_int32(server_port, 0, "Port for operation as a server"); +DEFINE_string(credential_type, "INSECURE_CREDENTIALS", + "Credential type for communication with driver"); static bool got_sigint = false; @@ -39,7 +41,8 @@ namespace grpc { namespace testing { static void RunServer() { - QpsWorker worker(FLAGS_driver_port, FLAGS_server_port); + QpsWorker worker(FLAGS_driver_port, FLAGS_server_port, + FLAGS_credential_type.c_str()); while (!got_sigint && !worker.Done()) { gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), diff --git a/test/cpp/util/create_test_channel.cc b/test/cpp/util/create_test_channel.cc index 68c6fe4622e..34b6d60d014 100644 --- a/test/cpp/util/create_test_channel.cc +++ b/test/cpp/util/create_test_channel.cc @@ -51,29 +51,31 @@ void AddProdSslType() { } // namespace -// When ssl is enabled, if server is empty, override_hostname is used to +// When cred_type is 'ssl', if server is empty, override_hostname is used to // create channel. Otherwise, connect to server and override hostname if // override_hostname is provided. -// When ssl is not enabled, override_hostname is ignored. +// When cred_type is not 'ssl', override_hostname is ignored. // Set use_prod_root to true to use the SSL root for connecting to google. // In this case, path to the roots pem file must be set via environment variable // GRPC_DEFAULT_SSL_ROOTS_FILE_PATH. // Otherwise, root for test SSL cert will be used. -// creds will be used to create a channel when enable_ssl is true. +// creds will be used to create a channel when cred_type is 'ssl'. // Use examples: // CreateTestChannel( -// "1.1.1.1:12345", "override.hostname.com", true, false, creds); -// CreateTestChannel("test.google.com:443", "", true, true, creds); +// "1.1.1.1:12345", "ssl", "override.hostname.com", false, creds); +// CreateTestChannel("test.google.com:443", "ssl", "", true, creds); // same as above -// CreateTestChannel("", "test.google.com:443", true, true, creds); +// CreateTestChannel("", "ssl", "test.google.com:443", true, creds); std::shared_ptr CreateTestChannel( - const grpc::string& server, const grpc::string& override_hostname, - bool enable_ssl, bool use_prod_roots, + const grpc::string& server, const grpc::string& cred_type, + const grpc::string& override_hostname, bool use_prod_roots, const std::shared_ptr& creds, const ChannelArguments& args) { ChannelArguments channel_args(args); std::shared_ptr channel_creds; - if (enable_ssl) { + if (cred_type.empty()) { + return CreateChannel(server, InsecureChannelCredentials()); + } else if (cred_type == testing::kTlsCredentialsType) { // cred_type == "ssl" if (use_prod_roots) { gpr_once_init(&g_once_init_add_prod_ssl_provider, &AddProdSslType); channel_creds = testing::GetCredentialsProvider()->GetChannelCredentials( @@ -95,10 +97,28 @@ std::shared_ptr CreateTestChannel( } return CreateCustomChannel(connect_to, channel_creds, channel_args); } else { - return CreateChannel(server, InsecureChannelCredentials()); + channel_creds = testing::GetCredentialsProvider()->GetChannelCredentials( + cred_type, &channel_args); + GPR_ASSERT(channel_creds != nullptr); + + return CreateChannel(server, channel_creds); } } +std::shared_ptr CreateTestChannel( + const grpc::string& server, const grpc::string& override_hostname, + bool enable_ssl, bool use_prod_roots, + const std::shared_ptr& creds, + const ChannelArguments& args) { + grpc::string type; + if (enable_ssl) { + type = testing::kTlsCredentialsType; + } + + return CreateTestChannel(server, type, override_hostname, use_prod_roots, + creds, args); +} + std::shared_ptr CreateTestChannel( const grpc::string& server, const grpc::string& override_hostname, bool enable_ssl, bool use_prod_roots, diff --git a/test/cpp/util/create_test_channel.h b/test/cpp/util/create_test_channel.h index 9b4b09171ef..e2ca8f99b40 100644 --- a/test/cpp/util/create_test_channel.h +++ b/test/cpp/util/create_test_channel.h @@ -44,6 +44,12 @@ std::shared_ptr CreateTestChannel( const std::shared_ptr& creds, const ChannelArguments& args); +std::shared_ptr CreateTestChannel( + const grpc::string& server, const grpc::string& cred_type, + const grpc::string& override_hostname, bool use_prod_roots, + const std::shared_ptr& creds, + const ChannelArguments& args); + std::shared_ptr CreateTestChannel( const grpc::string& server, const grpc::string& credential_type, const std::shared_ptr& creds); From fb1e164cd81bd15b7d2aad595510e0c083fb3d5b Mon Sep 17 00:00:00 2001 From: Alexander Polcyn Date: Tue, 11 Jul 2017 17:49:21 -0700 Subject: [PATCH 020/127] dont wait for gc to destroy calls on ruby server --- src/ruby/lib/grpc/generic/active_call.rb | 141 +++++++++++++++++----- src/ruby/lib/grpc/generic/bidi_call.rb | 62 +++++----- src/ruby/lib/grpc/generic/rpc_desc.rb | 4 +- src/ruby/spec/generic/active_call_spec.rb | 4 +- src/ruby/spec/generic/client_stub_spec.rb | 136 +++++++++++++++------ src/ruby/spec/generic/rpc_desc_spec.rb | 10 +- 6 files changed, 249 insertions(+), 108 deletions(-) diff --git a/src/ruby/lib/grpc/generic/active_call.rb b/src/ruby/lib/grpc/generic/active_call.rb index cb407d236d1..96c773a995d 100644 --- a/src/ruby/lib/grpc/generic/active_call.rb +++ b/src/ruby/lib/grpc/generic/active_call.rb @@ -40,7 +40,7 @@ end module GRPC # The ActiveCall class provides simple methods for sending marshallable # data to a call - class ActiveCall + class ActiveCall # rubocop:disable Metrics/ClassLength include Core::TimeConsts include Core::CallOps extend Forwardable @@ -100,6 +100,11 @@ module GRPC fail(ArgumentError, 'Already sent md') if started && metadata_to_send @metadata_to_send = metadata_to_send || {} unless started @send_initial_md_mutex = Mutex.new + + @output_stream_done = false + @input_stream_done = false + @call_finished = false + @call_finished_mu = Mutex.new end # Sends the initial metadata that has yet to be sent. @@ -142,11 +147,9 @@ module GRPC Operation.new(self) end - # finished waits until a client call is completed. - # - # It blocks until the remote endpoint acknowledges by sending a status. - def finished + def receive_and_check_status batch_result = @call.run_batch(RECV_STATUS_ON_CLIENT => nil) + set_input_stream_done attach_status_results_and_complete_call(batch_result) end @@ -155,8 +158,6 @@ module GRPC @call.trailing_metadata = recv_status_batch_result.status.metadata end @call.status = recv_status_batch_result.status - @call.close - op_is_done # The RECV_STATUS in run_batch always succeeds # Check the status for a bad status or failed run batch @@ -193,9 +194,19 @@ module GRPC } ops[RECV_CLOSE_ON_SERVER] = nil if assert_finished @call.run_batch(ops) + set_output_stream_done + nil end + # Intended for use on server-side calls when a single request from + # the client is expected (i.e., unary and server-streaming RPC types). + def read_unary_request + req = remote_read + set_input_stream_done + req + end + def server_unary_response(req, trailing_metadata: {}, code: Core::StatusCodes::OK, details: 'OK') ops = {} @@ -211,6 +222,7 @@ module GRPC ops[RECV_CLOSE_ON_SERVER] = nil @call.run_batch(ops) + set_output_stream_done end # remote_read reads a response from the remote endpoint. @@ -241,6 +253,8 @@ module GRPC # each_remote_read passes each response to the given block or returns an # enumerator the responses if no block is given. + # Used to generate the request enumerable for + # server-side client-streaming RPC's. # # == Enumerator == # @@ -258,10 +272,14 @@ module GRPC # @return [Enumerator] if no block was given def each_remote_read return enum_for(:each_remote_read) unless block_given? - loop do - resp = remote_read - break if resp.nil? # the last response was received - yield resp + begin + loop do + resp = remote_read + break if resp.nil? # the last response was received + yield resp + end + ensure + set_input_stream_done end end @@ -287,13 +305,17 @@ module GRPC # @return [Enumerator] if no block was given def each_remote_read_then_finish return enum_for(:each_remote_read_then_finish) unless block_given? - loop do - resp = remote_read - if resp.nil? # the last response was received, but not finished yet - finished - break + begin + loop do + resp = remote_read + if resp.nil? # the last response was received + receive_and_check_status + break + end + yield resp end - yield resp + ensure + set_input_stream_done end end @@ -319,7 +341,15 @@ module GRPC end @metadata_sent = true end - batch_result = @call.run_batch(ops) + + begin + batch_result = @call.run_batch(ops) + # no need to check for cancellation after a CallError because this + # batch contains a RECV_STATUS op + ensure + set_input_stream_done + set_output_stream_done + end @call.metadata = batch_result.metadata attach_status_results_and_complete_call(batch_result) @@ -339,10 +369,19 @@ module GRPC # a list, multiple metadata for its key are sent # @return [Object] the response received from the server def client_streamer(requests, metadata: {}) - # Metadata might have already been sent if this is an operation view - merge_metadata_and_send_if_not_already_sent(metadata) + begin + merge_metadata_and_send_if_not_already_sent(metadata) + requests.each { |r| @call.run_batch(SEND_MESSAGE => @marshal.call(r)) } + rescue GRPC::Core::CallError => e + receive_and_check_status # check for Cancelled + raise e + rescue => e + set_input_stream_done + raise e + ensure + set_output_stream_done + end - requests.each { |r| @call.run_batch(SEND_MESSAGE => @marshal.call(r)) } batch_result = @call.run_batch( SEND_CLOSE_FROM_CLIENT => nil, RECV_INITIAL_METADATA => nil, @@ -350,12 +389,11 @@ module GRPC RECV_STATUS_ON_CLIENT => nil ) + set_input_stream_done + @call.metadata = batch_result.metadata attach_status_results_and_complete_call(batch_result) get_message_from_batch_result(batch_result) - rescue GRPC::Core::CallError => e - finished # checks for Cancelled - raise e end # server_streamer sends one request to the GRPC server, which yields a @@ -384,13 +422,22 @@ module GRPC end @metadata_sent = true end - @call.run_batch(ops) + + begin + @call.run_batch(ops) + rescue GRPC::Core::CallError => e + receive_and_check_status # checks for Cancelled + raise e + rescue => e + set_input_stream_done + raise e + ensure + set_output_stream_done + end + replies = enum_for(:each_remote_read_then_finish) return replies unless block_given? replies.each { |r| yield r } - rescue GRPC::Core::CallError => e - finished # checks for Cancelled - raise e end # bidi_streamer sends a stream of requests to the GRPC server, and yields @@ -428,7 +475,10 @@ module GRPC @unmarshal, metadata_received: @metadata_received) - bd.run_on_client(requests, @op_notifier, &blk) + bd.run_on_client(requests, + proc { set_input_stream_done }, + proc { set_output_stream_done }, + &blk) end # run_server_bidi orchestrates a BiDi stream processing on a server. @@ -449,7 +499,7 @@ module GRPC metadata_received: @metadata_received, req_view: MultiReqView.new(self)) - bd.run_on_server(gen_each_reply) + bd.run_on_server(gen_each_reply, proc { set_input_stream_done }) end # Waits till an operation completes @@ -459,7 +509,8 @@ module GRPC @op_notifier.wait end - # Signals that an operation is done + # Signals that an operation is done. + # Only relevant on the client-side (this is a no-op on the server-side) def op_is_done return if @op_notifier.nil? @op_notifier.notify(self) @@ -486,6 +537,34 @@ module GRPC private + # To be called once the "input stream" has been completelly + # read through (i.e, done reading from client or received status) + # note this is idempotent + def set_input_stream_done + @call_finished_mu.synchronize do + @input_stream_done = true + maybe_finish_and_close_call_locked + end + end + + # To be called once the "output stream" has been completelly + # sent through (i.e, done sending from client or sent status) + # note this is idempotent + def set_output_stream_done + @call_finished_mu.synchronize do + @output_stream_done = true + maybe_finish_and_close_call_locked + end + end + + def maybe_finish_and_close_call_locked + return unless @output_stream_done && @input_stream_done + return if @call_finished + @call_finished = true + op_is_done + @call.close + end + # Starts the call if not already started # @param metadata [Hash] metadata to be sent to the server. If a value is # a list, multiple metadata for its key are sent diff --git a/src/ruby/lib/grpc/generic/bidi_call.rb b/src/ruby/lib/grpc/generic/bidi_call.rb index e54cf78969b..9e125cd986b 100644 --- a/src/ruby/lib/grpc/generic/bidi_call.rb +++ b/src/ruby/lib/grpc/generic/bidi_call.rb @@ -62,12 +62,19 @@ module GRPC # block that can be invoked with each response. # # @param requests the Enumerable of requests to send - # @param op_notifier a Notifier used to signal completion + # @param set_input_stream_done [Proc] called back when we're done + # reading the input stream + # @param set_input_stream_done [Proc] called back when we're done + # sending data on the output stream # @return an Enumerator of requests to yield - def run_on_client(requests, op_notifier, &blk) - @op_notifier = op_notifier - @enq_th = Thread.new { write_loop(requests) } - read_loop(&blk) + def run_on_client(requests, + set_input_stream_done, + set_output_stream_done, + &blk) + @enq_th = Thread.new do + write_loop(requests, set_output_stream_done: set_output_stream_done) + end + read_loop(set_input_stream_done, &blk) end # Begins orchestration of the Bidi stream for a server generating replies. @@ -81,12 +88,17 @@ module GRPC # produced by gen_each_reply could ignore the received_msgs # # @param gen_each_reply [Proc] generates the BiDi stream replies. - def run_on_server(gen_each_reply) + # @param set_input_steam_done [Proc] call back to call when + # the reads have been completely read through. + def run_on_server(gen_each_reply, set_input_stream_done) # Pass in the optional call object parameter if possible if gen_each_reply.arity == 1 - replys = gen_each_reply.call(read_loop(is_client: false)) + replys = gen_each_reply.call( + read_loop(set_input_stream_done, is_client: false)) elsif gen_each_reply.arity == 2 - replys = gen_each_reply.call(read_loop(is_client: false), @req_view) + replys = gen_each_reply.call( + read_loop(set_input_stream_done, is_client: false), + @req_view) else fail 'Illegal arity of reply generator' end @@ -99,22 +111,6 @@ module GRPC END_OF_READS = :end_of_reads END_OF_WRITES = :end_of_writes - # signals that bidi operation is complete - def notify_done - return unless @op_notifier - GRPC.logger.debug("bidi-notify-done: notifying #{@op_notifier}") - @op_notifier.notify(self) - end - - # signals that a bidi operation is complete (read + write) - def finished - @done_mutex.synchronize do - return unless @reads_complete && @writes_complete && !@complete - @call.close - @complete = true - end - end - # performs a read using @call.run_batch, ensures metadata is set up def read_using_run_batch ops = { RECV_MESSAGE => nil } @@ -127,7 +123,8 @@ module GRPC batch_result end - def write_loop(requests, is_client: true) + # set_output_stream_done is relevant on client-side + def write_loop(requests, is_client: true, set_output_stream_done: nil) GRPC.logger.debug('bidi-write-loop: starting') count = 0 requests.each do |req| @@ -151,23 +148,20 @@ module GRPC GRPC.logger.debug("bidi-write-loop: client sent #{count}, waiting") @call.run_batch(SEND_CLOSE_FROM_CLIENT => nil) GRPC.logger.debug('bidi-write-loop: done') - notify_done - @writes_complete = true - finished end GRPC.logger.debug('bidi-write-loop: finished') rescue StandardError => e GRPC.logger.warn('bidi-write-loop: failed') GRPC.logger.warn(e) - notify_done - @writes_complete = true - finished raise e + ensure + set_output_stream_done.call if is_client end # Provides an enumerator that yields results of remote reads - def read_loop(is_client: true) + def read_loop(set_input_stream_done, is_client: true) return enum_for(:read_loop, + set_input_stream_done, is_client: is_client) unless block_given? GRPC.logger.debug('bidi-read-loop: starting') begin @@ -201,10 +195,10 @@ module GRPC GRPC.logger.warn('bidi: read-loop failed') GRPC.logger.warn(e) raise e + ensure + set_input_stream_done.call end GRPC.logger.debug('bidi-read-loop: finished') - @reads_complete = true - finished # Make sure that the write loop is done done before finishing the call. # Note that blocking is ok at this point because we've already received # a status diff --git a/src/ruby/lib/grpc/generic/rpc_desc.rb b/src/ruby/lib/grpc/generic/rpc_desc.rb index ce0097573a6..89cf8ff6a0a 100644 --- a/src/ruby/lib/grpc/generic/rpc_desc.rb +++ b/src/ruby/lib/grpc/generic/rpc_desc.rb @@ -48,7 +48,7 @@ module GRPC end def handle_request_response(active_call, mth) - req = active_call.remote_read + req = active_call.read_unary_request resp = mth.call(req, active_call.single_req_view) active_call.server_unary_response( resp, trailing_metadata: active_call.output_metadata) @@ -61,7 +61,7 @@ module GRPC end def handle_server_streamer(active_call, mth) - req = active_call.remote_read + req = active_call.read_unary_request replys = mth.call(req, active_call.single_req_view) replys.each { |r| active_call.remote_send(r) } send_status(active_call, OK, 'OK', active_call.output_metadata) diff --git a/src/ruby/spec/generic/active_call_spec.rb b/src/ruby/spec/generic/active_call_spec.rb index 72e55ebcce0..ec0c2941741 100644 --- a/src/ruby/spec/generic/active_call_spec.rb +++ b/src/ruby/spec/generic/active_call_spec.rb @@ -473,7 +473,7 @@ describe GRPC::ActiveCall do server_call.remote_send('server_response') expect(client_call.remote_read).to eq('server_response') server_call.send_status(OK, 'status code is OK') - expect { client_call.finished }.to_not raise_error + expect { client_call.receive_and_check_status }.to_not raise_error end it 'finishes ok if the server sends an early status response' do @@ -490,7 +490,7 @@ describe GRPC::ActiveCall do expect do call.run_batch(CallOps::SEND_CLOSE_FROM_CLIENT => nil) end.to_not raise_error - expect { client_call.finished }.to_not raise_error + expect { client_call.receive_and_check_status }.to_not raise_error end it 'finishes ok if SEND_CLOSE and RECV_STATUS has been sent' do diff --git a/src/ruby/spec/generic/client_stub_spec.rb b/src/ruby/spec/generic/client_stub_spec.rb index 09b88c7cef4..3b8f72eda11 100644 --- a/src/ruby/spec/generic/client_stub_spec.rb +++ b/src/ruby/spec/generic/client_stub_spec.rb @@ -45,6 +45,7 @@ describe 'ClientStub' do @method = 'an_rpc_method' @pass = OK @fail = INTERNAL + @metadata = { k1: 'v1', k2: 'v2' } end after(:each) do @@ -107,7 +108,7 @@ describe 'ClientStub' do end end - describe '#request_response' do + describe '#request_response', request_response: true do before(:each) do @sent_msg, @resp = 'a_msg', 'a_reply' end @@ -187,13 +188,24 @@ describe 'ClientStub' do # Kill the server thread so tests can complete th.kill end + + it 'should raise ArgumentError if metadata contains invalid values' do + @metadata.merge!(k3: 3) + server_port = create_test_server + host = "localhost:#{server_port}" + stub = GRPC::ClientStub.new(host, :this_channel_is_insecure) + expect do + get_response(stub) + end.to raise_error(ArgumentError, + /Header values must be of type string or array/) + end end describe 'without a call operation' do def get_response(stub, credentials: nil) puts credentials.inspect stub.request_response(@method, @sent_msg, noop, noop, - metadata: { k1: 'v1', k2: 'v2' }, + metadata: @metadata, credentials: credentials) end @@ -201,16 +213,19 @@ describe 'ClientStub' do end describe 'via a call operation' do + after(:each) do + # make sure op.wait doesn't hang, even if there's a bad status + @op.wait + end def get_response(stub, run_start_call_first: false, credentials: nil) - op = stub.request_response(@method, @sent_msg, noop, noop, - return_op: true, - metadata: { k1: 'v1', k2: 'v2' }, - deadline: from_relative_time(2), - credentials: credentials) - expect(op).to be_a(GRPC::ActiveCall::Operation) - op.start_call if run_start_call_first - result = op.execute - op.wait # make sure wait doesn't hang + @op = stub.request_response(@method, @sent_msg, noop, noop, + return_op: true, + metadata: @metadata, + deadline: from_relative_time(2), + credentials: credentials) + expect(@op).to be_a(GRPC::ActiveCall::Operation) + @op.start_call if run_start_call_first + result = @op.execute result end @@ -228,13 +243,12 @@ describe 'ClientStub' do end end - describe '#client_streamer' do + describe '#client_streamer', client_streamer: true do before(:each) do Thread.abort_on_exception = true server_port = create_test_server host = "localhost:#{server_port}" @stub = GRPC::ClientStub.new(host, :this_channel_is_insecure) - @metadata = { k1: 'v1', k2: 'v2' } @sent_msgs = Array.new(3) { |i| 'msg_' + (i + 1).to_s } @resp = 'a_reply' end @@ -278,13 +292,16 @@ describe 'ClientStub' do end describe 'via a call operation' do + after(:each) do + # make sure op.wait doesn't hang, even if there's a bad status + @op.wait + end def get_response(stub, run_start_call_first: false) - op = stub.client_streamer(@method, @sent_msgs, noop, noop, - return_op: true, metadata: @metadata) - expect(op).to be_a(GRPC::ActiveCall::Operation) - op.start_call if run_start_call_first - result = op.execute - op.wait # make sure wait doesn't hang + @op = stub.client_streamer(@method, @sent_msgs, noop, noop, + return_op: true, metadata: @metadata) + expect(@op).to be_a(GRPC::ActiveCall::Operation) + @op.start_call if run_start_call_first + result = @op.execute result end @@ -298,7 +315,7 @@ describe 'ClientStub' do end end - describe '#server_streamer' do + describe '#server_streamer', server_streamer: true do before(:each) do @sent_msg = 'a_msg' @replys = Array.new(3) { |i| 'reply_' + (i + 1).to_s } @@ -334,12 +351,36 @@ describe 'ClientStub' do expect { e.collect { |r| r } }.to raise_error(GRPC::BadStatus) th.join end + + it 'should raise ArgumentError if metadata contains invalid values' do + @metadata.merge!(k3: 3) + server_port = create_test_server + host = "localhost:#{server_port}" + stub = GRPC::ClientStub.new(host, :this_channel_is_insecure) + expect do + get_responses(stub) + end.to raise_error(ArgumentError, + /Header values must be of type string or array/) + end + + it 'the call terminates when there is an unmarshalling error' do + server_port = create_test_server + host = "localhost:#{server_port}" + th = run_server_streamer(@sent_msg, @replys, @pass) + stub = GRPC::ClientStub.new(host, :this_channel_is_insecure) + + unmarshal = proc { fail(ArgumentError, 'test unmarshalling error') } + expect do + get_responses(stub, unmarshal: unmarshal).collect { |r| r } + end.to raise_error(ArgumentError, 'test unmarshalling error') + th.join + end end - describe 'without a call operation' do - def get_responses(stub) - e = stub.server_streamer(@method, @sent_msg, noop, noop, - metadata: { k1: 'v1', k2: 'v2' }) + describe 'without a call operation', test2: true do + def get_responses(stub, unmarshal: noop) + e = stub.server_streamer(@method, @sent_msg, noop, unmarshal, + metadata: @metadata) expect(e).to be_a(Enumerator) e end @@ -351,10 +392,10 @@ describe 'ClientStub' do after(:each) do @op.wait # make sure wait doesn't hang end - def get_responses(stub, run_start_call_first: false) - @op = stub.server_streamer(@method, @sent_msg, noop, noop, + def get_responses(stub, run_start_call_first: false, unmarshal: noop) + @op = stub.server_streamer(@method, @sent_msg, noop, unmarshal, return_op: true, - metadata: { k1: 'v1', k2: 'v2' }) + metadata: @metadata) expect(@op).to be_a(GRPC::ActiveCall::Operation) @op.start_call if run_start_call_first e = @op.execute @@ -377,7 +418,7 @@ describe 'ClientStub' do end end - describe '#bidi_streamer' do + describe '#bidi_streamer', bidi: true do before(:each) do @sent_msgs = Array.new(3) { |i| 'msg_' + (i + 1).to_s } @replys = Array.new(3) { |i| 'reply_' + (i + 1).to_s } @@ -386,7 +427,7 @@ describe 'ClientStub' do end shared_examples 'bidi streaming' do - it 'supports sending all the requests first', bidi: true do + it 'supports sending all the requests first' do th = run_bidi_streamer_handle_inputs_first(@sent_msgs, @replys, @pass) stub = GRPC::ClientStub.new(@host, :this_channel_is_insecure) @@ -395,7 +436,7 @@ describe 'ClientStub' do th.join end - it 'supports client-initiated ping pong', bidi: true do + it 'supports client-initiated ping pong' do th = run_bidi_streamer_echo_ping_pong(@sent_msgs, @pass, true) stub = GRPC::ClientStub.new(@host, :this_channel_is_insecure) e = get_responses(stub) @@ -403,18 +444,39 @@ describe 'ClientStub' do th.join end - it 'supports a server-initiated ping pong', bidi: true do + it 'supports a server-initiated ping pong' do th = run_bidi_streamer_echo_ping_pong(@sent_msgs, @pass, false) stub = GRPC::ClientStub.new(@host, :this_channel_is_insecure) e = get_responses(stub) expect(e.collect { |r| r }).to eq(@sent_msgs) th.join end + + it 'should raise an error if the status is not ok' do + th = run_bidi_streamer_echo_ping_pong(@sent_msgs, @fail, false) + stub = GRPC::ClientStub.new(@host, :this_channel_is_insecure) + e = get_responses(stub) + expect { e.collect { |r| r } }.to raise_error(GRPC::BadStatus) + th.join + end + + # TODO: add test for metadata-related ArgumentError in a bidi call once + # issue mentioned in https://github.com/grpc/grpc/issues/10526 is fixed + + it 'should send metadata to the server ok' do + th = run_bidi_streamer_echo_ping_pong(@sent_msgs, @pass, true, + **@metadata) + stub = GRPC::ClientStub.new(@host, :this_channel_is_insecure) + e = get_responses(stub) + expect(e.collect { |r| r }).to eq(@sent_msgs) + th.join + end end describe 'without a call operation' do def get_responses(stub) - e = stub.bidi_streamer(@method, @sent_msgs, noop, noop) + e = stub.bidi_streamer(@method, @sent_msgs, noop, noop, + metadata: @metadata) expect(e).to be_a(Enumerator) e end @@ -428,7 +490,8 @@ describe 'ClientStub' do end def get_responses(stub, run_start_call_first: false) @op = stub.bidi_streamer(@method, @sent_msgs, noop, noop, - return_op: true) + return_op: true, + metadata: @metadata) expect(@op).to be_a(GRPC::ActiveCall::Operation) @op.start_call if run_start_call_first e = @op.execute @@ -472,9 +535,14 @@ describe 'ClientStub' do end end - def run_bidi_streamer_echo_ping_pong(expected_inputs, status, client_starts) + def run_bidi_streamer_echo_ping_pong(expected_inputs, status, client_starts, + **kw) + wanted_metadata = kw.clone wakey_thread do |notifier| c = expect_server_to_be_invoked(notifier) + wanted_metadata.each do |k, v| + expect(c.metadata[k.to_s]).to eq(v) + end expected_inputs.each do |i| if client_starts expect(c.remote_read).to eq(i) diff --git a/src/ruby/spec/generic/rpc_desc_spec.rb b/src/ruby/spec/generic/rpc_desc_spec.rb index 100e9e84876..be578c40d3f 100644 --- a/src/ruby/spec/generic/rpc_desc_spec.rb +++ b/src/ruby/spec/generic/rpc_desc_spec.rb @@ -38,14 +38,14 @@ describe GRPC::RpcDesc do shared_examples 'it handles errors' do it 'sends the specified status if BadStatus is raised' do - expect(@call).to receive(:remote_read).once.and_return(Object.new) + expect(@call).to receive(:read_unary_request).once.and_return(Object.new) expect(@call).to receive(:send_status).once.with(@bs_code, 'NOK', false, metadata: {}) this_desc.run_server_method(@call, method(:bad_status)) end it 'sends status UNKNOWN if other StandardErrors are raised' do - expect(@call).to receive(:remote_read).once.and_return(Object.new) + expect(@call).to receive(:read_unary_request).once.and_return(Object.new) expect(@call).to receive(:send_status).once.with(UNKNOWN, arg_error_msg, false, metadata: {}) @@ -53,7 +53,7 @@ describe GRPC::RpcDesc do end it 'absorbs CallError with no further action' do - expect(@call).to receive(:remote_read).once.and_raise(CallError) + expect(@call).to receive(:read_unary_request).once.and_raise(CallError) blk = proc do this_desc.run_server_method(@call, method(:fake_reqresp)) end @@ -75,7 +75,7 @@ describe GRPC::RpcDesc do it 'sends a response and closes the stream if there no errors' do req = Object.new - expect(@call).to receive(:remote_read).once.and_return(req) + expect(@call).to receive(:read_unary_request).once.and_return(req) expect(@call).to receive(:output_metadata).once.and_return(fake_md) expect(@call).to receive(:server_unary_response).once .with(@ok_response, trailing_metadata: fake_md) @@ -133,7 +133,7 @@ describe GRPC::RpcDesc do it 'sends a response and closes the stream if there no errors' do req = Object.new - expect(@call).to receive(:remote_read).once.and_return(req) + expect(@call).to receive(:read_unary_request).once.and_return(req) expect(@call).to receive(:remote_send).twice.with(@ok_response) expect(@call).to receive(:output_metadata).and_return(fake_md) expect(@call).to receive(:send_status).once.with(OK, 'OK', true, From 6b08cf4c81f93f31d31e6c36124c0aff7919b3e8 Mon Sep 17 00:00:00 2001 From: Ian Coolidge Date: Fri, 16 Jun 2017 12:56:23 -0700 Subject: [PATCH 021/127] Propagate alwayslink in the grpc_cc_library build rule template. --- bazel/grpc_build_system.bzl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/bazel/grpc_build_system.bzl b/bazel/grpc_build_system.bzl index 8057f27a123..f793cae56d1 100644 --- a/bazel/grpc_build_system.bzl +++ b/bazel/grpc_build_system.bzl @@ -25,7 +25,8 @@ def grpc_cc_library(name, srcs = [], public_hdrs = [], hdrs = [], external_deps = [], deps = [], standalone = False, - language = "C++", testonly = False, visibility = None): + language = "C++", testonly = False, visibility = None, + alwayslink = 0): copts = [] if language.upper() == "C": copts = ["-std=c99"] @@ -40,7 +41,8 @@ def grpc_cc_library(name, srcs = [], public_hdrs = [], hdrs = [], linkopts = ["-pthread"], includes = [ "include" - ] + ], + alwayslink = alwayslink, ) def grpc_proto_plugin(name, srcs = [], deps = []): From 13213419f6381625a9d41622b94a31a91c0fc9c0 Mon Sep 17 00:00:00 2001 From: Ian Coolidge Date: Tue, 27 Jun 2017 21:49:44 -0700 Subject: [PATCH 022/127] alwayslink=1 for reflection plugin The reflection plugin uses a static initializer to enable itself, but no one depends on its symbols, so it gets optimized out. Set alwayslink in the reflection plugin to fix that. --- BUILD | 1 + 1 file changed, 1 insertion(+) diff --git a/BUILD b/BUILD index 26981ca35da..74d9a77cfeb 100644 --- a/BUILD +++ b/BUILD @@ -1522,6 +1522,7 @@ grpc_cc_library( ":grpc++", "//src/proto/grpc/reflection/v1alpha:reflection_proto", ], + alwayslink = 1, ) grpc_cc_library( From df1c5d6826af5c6cb3435ed7d4918d3cb91bb7e7 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Thu, 13 Jul 2017 16:05:01 -0700 Subject: [PATCH 023/127] Update to use correct error constructor --- src/core/ext/transport/chttp2/transport/parsing.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/ext/transport/chttp2/transport/parsing.c b/src/core/ext/transport/chttp2/transport/parsing.c index 0c8a718482e..9d46cfa22e6 100644 --- a/src/core/ext/transport/chttp2/transport/parsing.c +++ b/src/core/ext/transport/chttp2/transport/parsing.c @@ -660,7 +660,7 @@ static grpc_error *init_header_frame_parser(grpc_exec_ctx *exec_ctx, } else if (grpc_chttp2_stream_map_size(&t->stream_map) >= t->settings[GRPC_ACKED_SETTINGS] [GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS]) { - return GRPC_ERROR_CREATE("Max stream count exceeded"); + return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Max stream count exceeded"); } t->last_new_stream_id = t->incoming_stream_id; s = t->incoming_stream = From 8a08400af22a9ebf7e699b130a65833ce272ed87 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 14 Jul 2017 14:49:09 -0700 Subject: [PATCH 024/127] Fix spam --- tools/mkowners/mkowners.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tools/mkowners/mkowners.py b/tools/mkowners/mkowners.py index 2ccedfcfb8c..e0ad998bdc7 100755 --- a/tools/mkowners/mkowners.py +++ b/tools/mkowners/mkowners.py @@ -164,7 +164,6 @@ def expand_directives(root, directives): if intersect: for f in sorted(files_add): # sorted to ensure merge stability if f not in intersect: - print("X", root, glob_add, glob_have) out_globs[os.path.relpath(f, start=root)] = who_add for who in who_have: if who not in out_globs[glob_add]: @@ -185,7 +184,6 @@ def add_parent_to_globs(parent, globs, globs_dir): if intersect: for f in sorted(files_child): # sorted to ensure merge stability if f not in intersect: - print("Y", full_dir(owners.dir, oglob), full_dir(globs_dir, gglob)) who = gglob_who_orig.copy() globs[os.path.relpath(f, start=globs_dir)] = who for who in oglob_who: From c9caedd95ae9568bd05e7655002487e9900cbc39 Mon Sep 17 00:00:00 2001 From: Sree Kuchibhotla Date: Fri, 14 Jul 2017 15:46:51 -0700 Subject: [PATCH 025/127] fix compiler bug in epoll-ex --- src/core/lib/iomgr/ev_epollex_linux.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/lib/iomgr/ev_epollex_linux.c b/src/core/lib/iomgr/ev_epollex_linux.c index 24994173564..a2fa4ad9a5d 100644 --- a/src/core/lib/iomgr/ev_epollex_linux.c +++ b/src/core/lib/iomgr/ev_epollex_linux.c @@ -1049,8 +1049,8 @@ static grpc_error *pollset_add_fd_locked(grpc_exec_ctx *exec_ctx, /* Introduce a spurious completion. If we do not, then it may be that the fd-specific epoll set consumed a completion without being polled, leading to a missed edge going up. */ - grpc_lfev_set_ready(exec_ctx, &had_fd->read_closure); - grpc_lfev_set_ready(exec_ctx, &had_fd->write_closure); + grpc_lfev_set_ready(exec_ctx, &had_fd->read_closure, "read"); + grpc_lfev_set_ready(exec_ctx, &had_fd->write_closure, "write"); pollset_kick_all(exec_ctx, pollset); pollset->current_pollable = &pollset->pollable; if (append_error(&error, pollable_materialize(&pollset->pollable), From ac9fdfbc40507a6c5453b171561537ee9cafe61a Mon Sep 17 00:00:00 2001 From: Guantao Liu Date: Fri, 14 Jul 2017 17:33:19 -0700 Subject: [PATCH 026/127] Removed unnecessary default values and fixed sanity. --- test/cpp/qps/BUILD | 3 ++ test/cpp/qps/driver.cc | 34 ++++++++----------- test/cpp/qps/driver.h | 6 ++-- test/cpp/qps/qps_json_driver.cc | 8 ++--- test/cpp/qps/qps_openloop_test.cc | 5 +-- test/cpp/qps/qps_worker.cc | 8 ++--- test/cpp/qps/qps_worker.h | 4 +-- .../qps/secure_sync_unary_ping_pong_test.cc | 5 +-- test/cpp/qps/worker.cc | 6 ++-- 9 files changed, 40 insertions(+), 39 deletions(-) diff --git a/test/cpp/qps/BUILD b/test/cpp/qps/BUILD index e24aa0cd0a0..b3348b76fab 100644 --- a/test/cpp/qps/BUILD +++ b/test/cpp/qps/BUILD @@ -149,6 +149,7 @@ grpc_cc_binary( ":driver_impl", "//:grpc++", "//test/cpp/util:test_config", + "//test/cpp/util:test_util", ], external_deps = [ "gflags", @@ -163,6 +164,7 @@ grpc_cc_test( ":driver_impl", ":qps_worker_impl", "//test/cpp/util:test_config", + "//test/cpp/util:test_util", ], ) @@ -174,6 +176,7 @@ grpc_cc_test( ":driver_impl", "//:grpc++", "//test/cpp/util:test_config", + "//test/cpp/util:test_util", ], ) diff --git a/test/cpp/qps/driver.cc b/test/cpp/qps/driver.cc index bb4e7536e84..88d4d52abc0 100644 --- a/test/cpp/qps/driver.cc +++ b/test/cpp/qps/driver.cc @@ -175,13 +175,11 @@ static void postprocess_scenario_result(ScenarioResult* result) { sum(result->server_stats(), SvrPollCount) / histogram.Count()); auto server_queries_per_cpu_sec = - histogram.Count() / - (sum(result->server_stats(), ServerSystemTime) + - sum(result->server_stats(), ServerUserTime)); + histogram.Count() / (sum(result->server_stats(), ServerSystemTime) + + sum(result->server_stats(), ServerUserTime)); auto client_queries_per_cpu_sec = - histogram.Count() / - (sum(result->client_stats(), SystemTime) + - sum(result->client_stats(), UserTime)); + histogram.Count() / (sum(result->client_stats(), SystemTime) + + sum(result->client_stats(), UserTime)); result->mutable_summary()->set_server_queries_per_cpu_sec( server_queries_per_cpu_sec); @@ -193,7 +191,8 @@ std::unique_ptr RunScenario( const ClientConfig& initial_client_config, size_t num_clients, const ServerConfig& initial_server_config, size_t num_servers, int warmup_seconds, int benchmark_seconds, int spawn_local_worker_count, - const char* qps_server_target_override, const char* credential_type) { + const grpc::string& qps_server_target_override, + const grpc::string& credential_type) { // Log everything from the driver gpr_set_log_verbosity(GPR_LOG_SEVERITY_DEBUG); @@ -266,10 +265,9 @@ std::unique_ptr RunScenario( for (size_t i = 0; i < num_servers; i++) { gpr_log(GPR_INFO, "Starting server on %s (worker #%" PRIuPTR ")", workers[i].c_str(), i); - servers[i].stub = WorkerService::NewStub( - CreateChannel(workers[i], - GetCredentialsProvider()->GetChannelCredentials( - credential_type, &channel_args))); + servers[i].stub = WorkerService::NewStub(CreateChannel( + workers[i], GetCredentialsProvider()->GetChannelCredentials( + credential_type, &channel_args))); ServerConfig server_config = initial_server_config; if (server_config.core_limit() != 0) { @@ -316,9 +314,8 @@ std::unique_ptr RunScenario( gpr_log(GPR_INFO, "Starting client on %s (worker #%" PRIuPTR ")", worker.c_str(), i + num_servers); clients[i].stub = WorkerService::NewStub( - CreateChannel(worker, - GetCredentialsProvider()->GetChannelCredentials( - credential_type, &channel_args))); + CreateChannel(worker, GetCredentialsProvider()->GetChannelCredentials( + credential_type, &channel_args))); ClientConfig per_client_config = client_config; if (initial_client_config.core_limit() != 0) { @@ -503,7 +500,7 @@ std::unique_ptr RunScenario( return result; } -bool RunQuit(const char* credential_type) { +bool RunQuit(const grpc::string& credential_type) { // Get client, server lists bool result = true; auto workers = get_workers("QPS_WORKERS"); @@ -513,10 +510,9 @@ bool RunQuit(const char* credential_type) { ChannelArguments channel_args; for (size_t i = 0; i < workers.size(); i++) { - auto stub = WorkerService::NewStub( - CreateChannel(workers[i], - GetCredentialsProvider()->GetChannelCredentials( - credential_type, &channel_args))); + auto stub = WorkerService::NewStub(CreateChannel( + workers[i], GetCredentialsProvider()->GetChannelCredentials( + credential_type, &channel_args))); Void dummy; grpc::ClientContext ctx; ctx.set_wait_for_ready(true); diff --git a/test/cpp/qps/driver.h b/test/cpp/qps/driver.h index ddf75ce5872..29f2776d791 100644 --- a/test/cpp/qps/driver.h +++ b/test/cpp/qps/driver.h @@ -31,10 +31,10 @@ std::unique_ptr RunScenario( const grpc::testing::ClientConfig& client_config, size_t num_clients, const grpc::testing::ServerConfig& server_config, size_t num_servers, int warmup_seconds, int benchmark_seconds, int spawn_local_worker_count, - const char* qps_server_target_override = "", - const char* credential_type = "INSECURE_CREDENTIALS"); + const grpc::string& qps_server_target_override, + const grpc::string& credential_type); -bool RunQuit(const char* credential_type = "INSECURE_CREDENTIALS"); +bool RunQuit(const grpc::string& credential_type); } // namespace testing } // namespace grpc diff --git a/test/cpp/qps/qps_json_driver.cc b/test/cpp/qps/qps_json_driver.cc index d4698a7dc2f..cca59f64d8c 100644 --- a/test/cpp/qps/qps_json_driver.cc +++ b/test/cpp/qps/qps_json_driver.cc @@ -31,6 +31,7 @@ #include "test/cpp/qps/parse_json.h" #include "test/cpp/qps/report.h" #include "test/cpp/util/test_config.h" +#include "test/cpp/util/test_credentials_provider.h" DEFINE_string(scenarios_file, "", "JSON file containing an array of Scenario objects"); @@ -61,7 +62,7 @@ DEFINE_string(qps_server_target_override, "", DEFINE_string(json_file_out, "", "File to write the JSON output to."); -DEFINE_string(credential_type, "INSECURE_CREDENTIALS", +DEFINE_string(credential_type, grpc::testing::kInsecureCredentialsType, "Credential type for communication with workers"); namespace grpc { @@ -75,8 +76,7 @@ static std::unique_ptr RunAndReport(const Scenario& scenario, scenario.server_config(), scenario.num_servers(), scenario.warmup_seconds(), scenario.benchmark_seconds(), scenario.spawn_local_worker_count(), - FLAGS_qps_server_target_override.c_str(), - FLAGS_credential_type.c_str()); + FLAGS_qps_server_target_override, FLAGS_credential_type); // Amend the result with scenario config. Eventually we should adjust // RunScenario contract so we don't need to touch the result here. @@ -190,7 +190,7 @@ static bool QpsDriver() { } else if (scjson) { json = FLAGS_scenarios_json.c_str(); } else if (FLAGS_quit) { - return RunQuit(FLAGS_credential_type.c_str()); + return RunQuit(FLAGS_credential_type); } // Parse into an array of scenarios diff --git a/test/cpp/qps/qps_openloop_test.cc b/test/cpp/qps/qps_openloop_test.cc index 2f8a3d75f0c..069b3fa0768 100644 --- a/test/cpp/qps/qps_openloop_test.cc +++ b/test/cpp/qps/qps_openloop_test.cc @@ -25,6 +25,7 @@ #include "test/cpp/qps/driver.h" #include "test/cpp/qps/report.h" #include "test/cpp/util/test_config.h" +#include "test/cpp/util/test_credentials_provider.h" namespace grpc { namespace testing { @@ -48,8 +49,8 @@ static void RunQPS() { server_config.set_server_type(ASYNC_SERVER); server_config.set_async_server_threads(8); - const auto result = - RunScenario(client_config, 1, server_config, 1, WARMUP, BENCHMARK, -2); + const auto result = RunScenario(client_config, 1, server_config, 1, WARMUP, + BENCHMARK, -2, "", kInsecureCredentialsType); GetReporter()->ReportQPSPerCore(*result); GetReporter()->ReportLatency(*result); diff --git a/test/cpp/qps/qps_worker.cc b/test/cpp/qps/qps_worker.cc index 4db4c868241..d20bc1b074e 100644 --- a/test/cpp/qps/qps_worker.cc +++ b/test/cpp/qps/qps_worker.cc @@ -265,7 +265,7 @@ class WorkerServiceImpl final : public WorkerService::Service { }; QpsWorker::QpsWorker(int driver_port, int server_port, - const char* credential_type) { + const grpc::string& credential_type) { impl_.reset(new WorkerServiceImpl(server_port, this)); gpr_atm_rel_store(&done_, static_cast(0)); @@ -273,9 +273,9 @@ QpsWorker::QpsWorker(int driver_port, int server_port, gpr_join_host_port(&server_address, "::", driver_port); ServerBuilder builder; - builder.AddListeningPort(server_address, - GetCredentialsProvider()->GetServerCredentials( - credential_type)); + builder.AddListeningPort( + server_address, + GetCredentialsProvider()->GetServerCredentials(credential_type)); builder.RegisterService(impl_.get()); gpr_free(server_address); diff --git a/test/cpp/qps/qps_worker.h b/test/cpp/qps/qps_worker.h index ab5e26a10e4..32ff98da9b7 100644 --- a/test/cpp/qps/qps_worker.h +++ b/test/cpp/qps/qps_worker.h @@ -33,8 +33,8 @@ class WorkerServiceImpl; class QpsWorker { public: - explicit QpsWorker(int driver_port, int server_port = 0, - const char* credential_type = "INSECURE_CREDENTIALS"); + explicit QpsWorker(int driver_port, int server_port, + const grpc::string& credential_type); ~QpsWorker(); bool Done() const; diff --git a/test/cpp/qps/secure_sync_unary_ping_pong_test.cc b/test/cpp/qps/secure_sync_unary_ping_pong_test.cc index 1ee6e374749..137b33ee25f 100644 --- a/test/cpp/qps/secure_sync_unary_ping_pong_test.cc +++ b/test/cpp/qps/secure_sync_unary_ping_pong_test.cc @@ -24,6 +24,7 @@ #include "test/cpp/qps/driver.h" #include "test/cpp/qps/report.h" #include "test/cpp/util/test_config.h" +#include "test/cpp/util/test_credentials_provider.h" namespace grpc { namespace testing { @@ -51,8 +52,8 @@ static void RunSynchronousUnaryPingPong() { client_config.mutable_security_params()->CopyFrom(security); server_config.mutable_security_params()->CopyFrom(security); - const auto result = - RunScenario(client_config, 1, server_config, 1, WARMUP, BENCHMARK, -2); + const auto result = RunScenario(client_config, 1, server_config, 1, WARMUP, + BENCHMARK, -2, "", kInsecureCredentialsType); GetReporter()->ReportQPS(*result); GetReporter()->ReportLatency(*result); diff --git a/test/cpp/qps/worker.cc b/test/cpp/qps/worker.cc index 7a8036327f6..27010b73152 100644 --- a/test/cpp/qps/worker.cc +++ b/test/cpp/qps/worker.cc @@ -27,10 +27,11 @@ #include "test/cpp/qps/qps_worker.h" #include "test/cpp/util/test_config.h" +#include "test/cpp/util/test_credentials_provider.h" DEFINE_int32(driver_port, 0, "Port for communication with driver"); DEFINE_int32(server_port, 0, "Port for operation as a server"); -DEFINE_string(credential_type, "INSECURE_CREDENTIALS", +DEFINE_string(credential_type, grpc::testing::kInsecureCredentialsType, "Credential type for communication with driver"); static bool got_sigint = false; @@ -41,8 +42,7 @@ namespace grpc { namespace testing { static void RunServer() { - QpsWorker worker(FLAGS_driver_port, FLAGS_server_port, - FLAGS_credential_type.c_str()); + QpsWorker worker(FLAGS_driver_port, FLAGS_server_port, FLAGS_credential_type); while (!got_sigint && !worker.Done()) { gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), From 91d8f0b5a846553ed11d0908129aaad116f63be4 Mon Sep 17 00:00:00 2001 From: Guantao Liu Date: Fri, 14 Jul 2017 18:33:30 -0700 Subject: [PATCH 027/127] Added the missing header file and fixed a syntax error. --- test/cpp/qps/driver.cc | 3 +-- test/cpp/qps/qps_worker.h | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/cpp/qps/driver.cc b/test/cpp/qps/driver.cc index 88d4d52abc0..4458e389e7e 100644 --- a/test/cpp/qps/driver.cc +++ b/test/cpp/qps/driver.cc @@ -285,8 +285,7 @@ std::unique_ptr RunScenario( if (!servers[i].stream->Read(&init_status)) { gpr_log(GPR_ERROR, "Server %zu did not yield initial status", i); } - if (qps_server_target_override != NULL && - strlen(qps_server_target_override) > 0) { + if (qps_server_target_override.length() > 0) { // overriding the qps server target only works if there is 1 server GPR_ASSERT(num_servers == 1); client_config.add_server_targets(qps_server_target_override); diff --git a/test/cpp/qps/qps_worker.h b/test/cpp/qps/qps_worker.h index 32ff98da9b7..5c1d1a8ae64 100644 --- a/test/cpp/qps/qps_worker.h +++ b/test/cpp/qps/qps_worker.h @@ -22,6 +22,7 @@ #include #include +#include namespace grpc { From 29a7050c357e64639c0f1bf699489659e34778ee Mon Sep 17 00:00:00 2001 From: Guantao Liu Date: Fri, 14 Jul 2017 19:24:26 -0700 Subject: [PATCH 028/127] Fixed sanity. --- test/cpp/qps/qps_worker.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/cpp/qps/qps_worker.h b/test/cpp/qps/qps_worker.h index 5c1d1a8ae64..360125fb170 100644 --- a/test/cpp/qps/qps_worker.h +++ b/test/cpp/qps/qps_worker.h @@ -21,8 +21,8 @@ #include -#include #include +#include namespace grpc { From 0fd37e1951ae541d873d0f2803ebeb88d9c9f848 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Thu, 13 Jul 2017 21:07:29 -0700 Subject: [PATCH 029/127] Transport - Fix a bug in decompression path --- .../chttp2/transport/chttp2_transport.c | 45 ++++++++++++++++--- 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c index 00b0738b20d..1427b8f3302 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c @@ -1671,9 +1671,8 @@ void grpc_chttp2_maybe_complete_recv_message(grpc_exec_ctx *exec_ctx, } if (s->stream_compression_recv_enabled && !s->unprocessed_incoming_frames_decompressed) { - grpc_slice_buffer decompressed_data; + GPR_ASSERT(s->decompressed_data_buffer.length == 0); bool end_of_context; - grpc_slice_buffer_init(&decompressed_data); if (!s->stream_decompression_ctx) { s->stream_decompression_ctx = grpc_stream_compression_context_create( @@ -1681,17 +1680,18 @@ void grpc_chttp2_maybe_complete_recv_message(grpc_exec_ctx *exec_ctx, } if (!grpc_stream_decompress(s->stream_decompression_ctx, &s->unprocessed_incoming_frames_buffer, - &decompressed_data, NULL, 5, + &s->decompressed_data_buffer, NULL, 5, &end_of_context)) { grpc_slice_buffer_reset_and_unref_internal(exec_ctx, &s->frame_storage); grpc_slice_buffer_reset_and_unref_internal( exec_ctx, &s->unprocessed_incoming_frames_buffer); - s->seen_error = true; + error = + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Stream decompression error."); } else { error = grpc_deframe_unprocessed_incoming_frames( - exec_ctx, &s->data_parser, s, &decompressed_data, NULL, - s->recv_message); + exec_ctx, &s->data_parser, s, &s->decompressed_data_buffer, + NULL, s->recv_message); if (end_of_context) { grpc_stream_compression_context_destroy( s->stream_decompression_ctx); @@ -1740,7 +1740,38 @@ void grpc_chttp2_maybe_complete_recv_trailing_metadata(grpc_exec_ctx *exec_ctx, } bool pending_data = s->pending_byte_stream || s->unprocessed_incoming_frames_buffer.length > 0; - if (s->read_closed && s->frame_storage.length == 0 && + if (s->stream_compression_recv_enabled && s->read_closed && + s->frame_storage.length > 0 && + s->unprocessed_incoming_frames_buffer.length == 0 && !pending_data && + !s->seen_error && s->recv_trailing_metadata_finished != NULL) { + /* Maybe some SYNC_FLUSH data is left in frame_storage. Consume them and + * maybe decompress the next 5 bytes in the stream. */ + bool end_of_context; + if (!s->stream_decompression_ctx) { + s->stream_decompression_ctx = + grpc_stream_compression_context_create( + GRPC_STREAM_COMPRESSION_DECOMPRESS); + } + if (!grpc_stream_decompress(s->stream_decompression_ctx, + &s->frame_storage, + &s->unprocessed_incoming_frames_buffer, + NULL, 5, &end_of_context)) { + grpc_slice_buffer_reset_and_unref_internal(exec_ctx, + &s->frame_storage); + grpc_slice_buffer_reset_and_unref_internal( + exec_ctx, &s->unprocessed_incoming_frames_buffer); + s->seen_error = true; + } else { + if (s->unprocessed_incoming_frames_buffer.length > 0) { + s->unprocessed_incoming_frames_decompressed = true; + } + if (end_of_context) { + grpc_stream_compression_context_destroy(s->stream_decompression_ctx); + s->stream_decompression_ctx = NULL; + } + } + } + if (s->read_closed && s->frame_storage.length == 0 && s->unprocessed_incoming_frames_buffer.length == 0 && (!pending_data || s->seen_error) && s->recv_trailing_metadata_finished != NULL) { grpc_chttp2_incoming_metadata_buffer_publish( From 54c31c782f069270f9ba380f6959be22e50d745b Mon Sep 17 00:00:00 2001 From: Sree Kuchibhotla Date: Mon, 17 Jul 2017 14:57:27 -0700 Subject: [PATCH 030/127] release the g_epfd whent he engine is shutdown --- src/core/lib/iomgr/ev_epoll1_linux.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/lib/iomgr/ev_epoll1_linux.c b/src/core/lib/iomgr/ev_epoll1_linux.c index fb54e9c9547..dfe2d143a50 100644 --- a/src/core/lib/iomgr/ev_epoll1_linux.c +++ b/src/core/lib/iomgr/ev_epoll1_linux.c @@ -965,6 +965,7 @@ static void pollset_set_del_pollset_set(grpc_exec_ctx *exec_ctx, static void shutdown_engine(void) { fd_global_shutdown(); pollset_global_shutdown(); + close(g_epfd); } static const grpc_event_engine_vtable vtable = { From dfda37f5183176d711102135617534c4f0a5ea19 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Mon, 17 Jul 2017 15:15:31 -0700 Subject: [PATCH 031/127] transport - Fix uninitialized variable --- src/core/ext/transport/chttp2/transport/writing.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/ext/transport/chttp2/transport/writing.c b/src/core/ext/transport/chttp2/transport/writing.c index d7221eaf30a..dd20ff61aeb 100644 --- a/src/core/ext/transport/chttp2/transport/writing.c +++ b/src/core/ext/transport/chttp2/transport/writing.c @@ -315,8 +315,8 @@ grpc_chttp2_begin_write_result grpc_chttp2_begin_write( [GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE], GPR_MIN(stream_outgoing_window, t->outgoing_window)); if (max_outgoing > 0) { - bool is_last_data_frame; - bool is_last_frame; + bool is_last_data_frame = false; + bool is_last_frame = false; if (s->stream_compression_send_enabled) { while ((s->flow_controlled_buffer.length > 0 || s->compressed_data_buffer.length > 0) && From 26b33dedc2c065213070e4f820ca65365f712150 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Mon, 17 Jul 2017 15:15:53 -0700 Subject: [PATCH 032/127] transport - clang-format --- .../chttp2/transport/chttp2_transport.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c index 1427b8f3302..d6c2ce7b05c 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c @@ -1686,8 +1686,8 @@ void grpc_chttp2_maybe_complete_recv_message(grpc_exec_ctx *exec_ctx, &s->frame_storage); grpc_slice_buffer_reset_and_unref_internal( exec_ctx, &s->unprocessed_incoming_frames_buffer); - error = - GRPC_ERROR_CREATE_FROM_STATIC_STRING("Stream decompression error."); + error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Stream decompression error."); } else { error = grpc_deframe_unprocessed_incoming_frames( exec_ctx, &s->data_parser, s, &s->decompressed_data_buffer, @@ -1748,16 +1748,14 @@ void grpc_chttp2_maybe_complete_recv_trailing_metadata(grpc_exec_ctx *exec_ctx, * maybe decompress the next 5 bytes in the stream. */ bool end_of_context; if (!s->stream_decompression_ctx) { - s->stream_decompression_ctx = - grpc_stream_compression_context_create( - GRPC_STREAM_COMPRESSION_DECOMPRESS); + s->stream_decompression_ctx = grpc_stream_compression_context_create( + GRPC_STREAM_COMPRESSION_DECOMPRESS); } if (!grpc_stream_decompress(s->stream_decompression_ctx, &s->frame_storage, - &s->unprocessed_incoming_frames_buffer, - NULL, 5, &end_of_context)) { - grpc_slice_buffer_reset_and_unref_internal(exec_ctx, - &s->frame_storage); + &s->unprocessed_incoming_frames_buffer, NULL, + 5, &end_of_context)) { + grpc_slice_buffer_reset_and_unref_internal(exec_ctx, &s->frame_storage); grpc_slice_buffer_reset_and_unref_internal( exec_ctx, &s->unprocessed_incoming_frames_buffer); s->seen_error = true; @@ -1771,7 +1769,8 @@ void grpc_chttp2_maybe_complete_recv_trailing_metadata(grpc_exec_ctx *exec_ctx, } } } - if (s->read_closed && s->frame_storage.length == 0 && s->unprocessed_incoming_frames_buffer.length == 0 && + if (s->read_closed && s->frame_storage.length == 0 && + s->unprocessed_incoming_frames_buffer.length == 0 && (!pending_data || s->seen_error) && s->recv_trailing_metadata_finished != NULL) { grpc_chttp2_incoming_metadata_buffer_publish( From d40a7ae6c34a97c06e9bef3dc1a6e9774c5bf93c Mon Sep 17 00:00:00 2001 From: Yuchen Zeng Date: Wed, 12 Jul 2017 15:59:56 -0700 Subject: [PATCH 033/127] Add already_closed in grpc_fd_orphan --- .../resolver/dns/c_ares/grpc_ares_ev_driver_posix.c | 7 +++---- src/core/lib/iomgr/ev_epoll1_linux.c | 4 ++-- src/core/lib/iomgr/ev_epoll_limited_pollers_linux.c | 5 ++--- src/core/lib/iomgr/ev_epoll_thread_pool_linux.c | 6 +++--- src/core/lib/iomgr/ev_epollex_linux.c | 6 +++--- src/core/lib/iomgr/ev_epollsig_linux.c | 5 ++--- src/core/lib/iomgr/ev_poll_posix.c | 7 +++++-- src/core/lib/iomgr/ev_posix.c | 5 +++-- src/core/lib/iomgr/ev_posix.h | 4 ++-- src/core/lib/iomgr/tcp_client_posix.c | 6 ++++-- src/core/lib/iomgr/tcp_posix.c | 2 +- src/core/lib/iomgr/tcp_server_posix.c | 2 +- src/core/lib/iomgr/udp_server.c | 2 +- test/core/iomgr/ev_epollsig_linux_test.c | 6 ++++-- test/core/iomgr/fd_posix_test.c | 11 +++++++---- test/core/iomgr/pollset_set_test.c | 3 ++- 16 files changed, 45 insertions(+), 36 deletions(-) diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c index 1ab8295e9ec..b696344eaba 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c @@ -103,10 +103,9 @@ static void fd_node_destroy(grpc_exec_ctx *exec_ctx, fd_node *fdn) { grpc_pollset_set_del_fd(exec_ctx, fdn->ev_driver->pollset_set, fdn->grpc_fd); /* c-ares library has closed the fd inside grpc_fd. This fd may be picked up immediately by another thread, and should not be closed by the following - grpc_fd_orphan. To prevent this fd from being closed by grpc_fd_orphan, - a fd pointer is provided. */ - int fd; - grpc_fd_orphan(exec_ctx, fdn->grpc_fd, NULL, &fd, "c-ares query finished"); + grpc_fd_orphan. */ + grpc_fd_orphan(exec_ctx, fdn->grpc_fd, NULL, NULL, true /* already_closed */, + "c-ares query finished"); gpr_free(fdn); } diff --git a/src/core/lib/iomgr/ev_epoll1_linux.c b/src/core/lib/iomgr/ev_epoll1_linux.c index 66ba601adb9..b37ccca90ab 100644 --- a/src/core/lib/iomgr/ev_epoll1_linux.c +++ b/src/core/lib/iomgr/ev_epoll1_linux.c @@ -224,7 +224,7 @@ static void fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_error *why) { static void fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure *on_done, int *release_fd, - const char *reason) { + bool already_closed, const char *reason) { grpc_error *error = GRPC_ERROR_NONE; if (!grpc_lfev_is_shutdown(&fd->read_closure)) { @@ -235,7 +235,7 @@ static void fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd, descriptor fd->fd (but we still own the grpc_fd structure). */ if (release_fd != NULL) { *release_fd = fd->fd; - } else { + } else if (!already_closed) { close(fd->fd); } diff --git a/src/core/lib/iomgr/ev_epoll_limited_pollers_linux.c b/src/core/lib/iomgr/ev_epoll_limited_pollers_linux.c index 27b4892d1da..3e8c0ef91ee 100644 --- a/src/core/lib/iomgr/ev_epoll_limited_pollers_linux.c +++ b/src/core/lib/iomgr/ev_epoll_limited_pollers_linux.c @@ -931,7 +931,7 @@ static int fd_wrapped_fd(grpc_fd *fd) { static void fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure *on_done, int *release_fd, - const char *reason) { + bool already_closed, const char *reason) { grpc_error *error = GRPC_ERROR_NONE; polling_island *unref_pi = NULL; @@ -952,8 +952,7 @@ static void fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd, before doing this.) */ if (fd->po.pi != NULL) { polling_island *pi_latest = polling_island_lock(fd->po.pi); - polling_island_remove_fd_locked(pi_latest, fd, false /* is_fd_closed */, - &error); + polling_island_remove_fd_locked(pi_latest, fd, already_closed, &error); gpr_mu_unlock(&pi_latest->mu); unref_pi = fd->po.pi; diff --git a/src/core/lib/iomgr/ev_epoll_thread_pool_linux.c b/src/core/lib/iomgr/ev_epoll_thread_pool_linux.c index 49be72c03e0..68399b7f54d 100644 --- a/src/core/lib/iomgr/ev_epoll_thread_pool_linux.c +++ b/src/core/lib/iomgr/ev_epoll_thread_pool_linux.c @@ -493,8 +493,8 @@ static int fd_wrapped_fd(grpc_fd *fd) { static void fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure *on_done, int *release_fd, - const char *reason) { - bool is_fd_closed = false; + bool already_closed, const char *reason) { + bool is_fd_closed = already_closed; grpc_error *error = GRPC_ERROR_NONE; epoll_set *unref_eps = NULL; @@ -505,7 +505,7 @@ static void fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd, descriptor fd->fd (but we still own the grpc_fd structure). */ if (release_fd != NULL) { *release_fd = fd->fd; - } else { + } else if (!is_fd_closed) { close(fd->fd); is_fd_closed = true; } diff --git a/src/core/lib/iomgr/ev_epollex_linux.c b/src/core/lib/iomgr/ev_epollex_linux.c index 56904317592..b02725234e4 100644 --- a/src/core/lib/iomgr/ev_epollex_linux.c +++ b/src/core/lib/iomgr/ev_epollex_linux.c @@ -380,8 +380,8 @@ static int fd_wrapped_fd(grpc_fd *fd) { static void fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure *on_done, int *release_fd, - const char *reason) { - bool is_fd_closed = false; + bool already_closed, const char *reason) { + bool is_fd_closed = already_closed; grpc_error *error = GRPC_ERROR_NONE; gpr_mu_lock(&fd->pollable.po.mu); @@ -392,7 +392,7 @@ static void fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd, descriptor fd->fd (but we still own the grpc_fd structure). */ if (release_fd != NULL) { *release_fd = fd->fd; - } else { + } else if (!is_fd_closed) { close(fd->fd); is_fd_closed = true; } diff --git a/src/core/lib/iomgr/ev_epollsig_linux.c b/src/core/lib/iomgr/ev_epollsig_linux.c index 0d969dccce9..81ef8760c80 100644 --- a/src/core/lib/iomgr/ev_epollsig_linux.c +++ b/src/core/lib/iomgr/ev_epollsig_linux.c @@ -854,7 +854,7 @@ static int fd_wrapped_fd(grpc_fd *fd) { static void fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure *on_done, int *release_fd, - const char *reason) { + bool already_closed, const char *reason) { grpc_error *error = GRPC_ERROR_NONE; polling_island *unref_pi = NULL; @@ -875,8 +875,7 @@ static void fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd, before doing this.) */ if (fd->po.pi != NULL) { polling_island *pi_latest = polling_island_lock(fd->po.pi); - polling_island_remove_fd_locked(pi_latest, fd, false /* is_fd_closed */, - &error); + polling_island_remove_fd_locked(pi_latest, fd, already_closed, &error); gpr_mu_unlock(&pi_latest->mu); unref_pi = fd->po.pi; diff --git a/src/core/lib/iomgr/ev_poll_posix.c b/src/core/lib/iomgr/ev_poll_posix.c index 1f8d7eef26d..365aa583bb8 100644 --- a/src/core/lib/iomgr/ev_poll_posix.c +++ b/src/core/lib/iomgr/ev_poll_posix.c @@ -398,11 +398,14 @@ static int fd_wrapped_fd(grpc_fd *fd) { static void fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure *on_done, int *release_fd, - const char *reason) { + bool already_closed, const char *reason) { fd->on_done_closure = on_done; fd->released = release_fd != NULL; - if (fd->released) { + if (release_fd != NULL) { *release_fd = fd->fd; + fd->released = true; + } else if (already_closed) { + fd->released = true; } gpr_mu_lock(&fd->mu); REF_BY(fd, 1, reason); /* remove active status, but keep referenced */ diff --git a/src/core/lib/iomgr/ev_posix.c b/src/core/lib/iomgr/ev_posix.c index cff77e641c5..91f8cd54821 100644 --- a/src/core/lib/iomgr/ev_posix.c +++ b/src/core/lib/iomgr/ev_posix.c @@ -170,8 +170,9 @@ int grpc_fd_wrapped_fd(grpc_fd *fd) { } void grpc_fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure *on_done, - int *release_fd, const char *reason) { - g_event_engine->fd_orphan(exec_ctx, fd, on_done, release_fd, reason); + int *release_fd, bool already_closed, const char *reason) { + g_event_engine->fd_orphan(exec_ctx, fd, on_done, release_fd, already_closed, + reason); } void grpc_fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_error *why) { diff --git a/src/core/lib/iomgr/ev_posix.h b/src/core/lib/iomgr/ev_posix.h index 0de73338433..1108e46ef81 100644 --- a/src/core/lib/iomgr/ev_posix.h +++ b/src/core/lib/iomgr/ev_posix.h @@ -37,7 +37,7 @@ typedef struct grpc_event_engine_vtable { grpc_fd *(*fd_create)(int fd, const char *name); int (*fd_wrapped_fd)(grpc_fd *fd); void (*fd_orphan)(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure *on_done, - int *release_fd, const char *reason); + int *release_fd, bool already_closed, const char *reason); void (*fd_shutdown)(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_error *why); void (*fd_notify_on_read)(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure *closure); @@ -104,7 +104,7 @@ int grpc_fd_wrapped_fd(grpc_fd *fd); notify_on_write. MUST NOT be called with a pollset lock taken */ void grpc_fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure *on_done, - int *release_fd, const char *reason); + int *release_fd, bool already_closed, const char *reason); /* Has grpc_fd_shutdown been called on an fd? */ bool grpc_fd_is_shutdown(grpc_fd *fd); diff --git a/src/core/lib/iomgr/tcp_client_posix.c b/src/core/lib/iomgr/tcp_client_posix.c index 21e320a6e73..a25fba45279 100644 --- a/src/core/lib/iomgr/tcp_client_posix.c +++ b/src/core/lib/iomgr/tcp_client_posix.c @@ -209,7 +209,8 @@ static void on_writable(grpc_exec_ctx *exec_ctx, void *acp, grpc_error *error) { finish: if (fd != NULL) { grpc_pollset_set_del_fd(exec_ctx, ac->interested_parties, fd); - grpc_fd_orphan(exec_ctx, fd, NULL, NULL, "tcp_client_orphan"); + grpc_fd_orphan(exec_ctx, fd, NULL, NULL, false /* already_closed */, + "tcp_client_orphan"); fd = NULL; } done = (--ac->refs == 0); @@ -295,7 +296,8 @@ static void tcp_client_connect_impl(grpc_exec_ctx *exec_ctx, } if (errno != EWOULDBLOCK && errno != EINPROGRESS) { - grpc_fd_orphan(exec_ctx, fdobj, NULL, NULL, "tcp_client_connect_error"); + grpc_fd_orphan(exec_ctx, fdobj, NULL, NULL, false /* already_closed */, + "tcp_client_connect_error"); GRPC_CLOSURE_SCHED(exec_ctx, closure, GRPC_OS_ERROR(errno, "connect")); goto done; } diff --git a/src/core/lib/iomgr/tcp_posix.c b/src/core/lib/iomgr/tcp_posix.c index b6dcd15cb08..2f543fd8a9e 100644 --- a/src/core/lib/iomgr/tcp_posix.c +++ b/src/core/lib/iomgr/tcp_posix.c @@ -156,7 +156,7 @@ static void tcp_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, static void tcp_free(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) { grpc_fd_orphan(exec_ctx, tcp->em_fd, tcp->release_fd_cb, tcp->release_fd, - "tcp_unref_orphan"); + false /* already_closed */, "tcp_unref_orphan"); grpc_slice_buffer_destroy_internal(exec_ctx, &tcp->last_read_buffer); grpc_resource_user_unref(exec_ctx, tcp->resource_user); gpr_free(tcp->peer_string); diff --git a/src/core/lib/iomgr/tcp_server_posix.c b/src/core/lib/iomgr/tcp_server_posix.c index f304642951e..0fc5c0fd867 100644 --- a/src/core/lib/iomgr/tcp_server_posix.c +++ b/src/core/lib/iomgr/tcp_server_posix.c @@ -166,7 +166,7 @@ static void deactivated_all_ports(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) { GRPC_CLOSURE_INIT(&sp->destroyed_closure, destroyed_port, s, grpc_schedule_on_exec_ctx); grpc_fd_orphan(exec_ctx, sp->emfd, &sp->destroyed_closure, NULL, - "tcp_listener_shutdown"); + false /* already_closed */, "tcp_listener_shutdown"); } gpr_mu_unlock(&s->mu); } else { diff --git a/src/core/lib/iomgr/udp_server.c b/src/core/lib/iomgr/udp_server.c index 54e7f417a7c..88fa34cb7a6 100644 --- a/src/core/lib/iomgr/udp_server.c +++ b/src/core/lib/iomgr/udp_server.c @@ -214,7 +214,7 @@ static void deactivated_all_ports(grpc_exec_ctx *exec_ctx, grpc_udp_server *s) { sp->server->user_data); } grpc_fd_orphan(exec_ctx, sp->emfd, &sp->destroyed_closure, NULL, - "udp_listener_shutdown"); + false /* already_closed */, "udp_listener_shutdown"); } gpr_mu_unlock(&s->mu); } else { diff --git a/test/core/iomgr/ev_epollsig_linux_test.c b/test/core/iomgr/ev_epollsig_linux_test.c index 1d272fa4065..c702065d4d6 100644 --- a/test/core/iomgr/ev_epollsig_linux_test.c +++ b/test/core/iomgr/ev_epollsig_linux_test.c @@ -79,7 +79,8 @@ static void test_fd_cleanup(grpc_exec_ctx *exec_ctx, test_fd *tfds, GRPC_ERROR_CREATE_FROM_STATIC_STRING("test_fd_cleanup")); grpc_exec_ctx_flush(exec_ctx); - grpc_fd_orphan(exec_ctx, tfds[i].fd, NULL, &release_fd, "test_fd_cleanup"); + grpc_fd_orphan(exec_ctx, tfds[i].fd, NULL, &release_fd, + false /* already_closed */, "test_fd_cleanup"); grpc_exec_ctx_flush(exec_ctx); GPR_ASSERT(release_fd == tfds[i].inner_fd); @@ -294,7 +295,8 @@ static void test_threading(void) { { grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_fd_shutdown(&exec_ctx, shared.wakeup_desc, GRPC_ERROR_CANCELLED); - grpc_fd_orphan(&exec_ctx, shared.wakeup_desc, NULL, NULL, "done"); + grpc_fd_orphan(&exec_ctx, shared.wakeup_desc, NULL, NULL, + false /* already_closed */, "done"); grpc_pollset_shutdown(&exec_ctx, shared.pollset, GRPC_CLOSURE_CREATE(destroy_pollset, shared.pollset, grpc_schedule_on_exec_ctx)); diff --git a/test/core/iomgr/fd_posix_test.c b/test/core/iomgr/fd_posix_test.c index 02596450d22..85d5d9c07f3 100644 --- a/test/core/iomgr/fd_posix_test.c +++ b/test/core/iomgr/fd_posix_test.c @@ -114,7 +114,8 @@ static void session_shutdown_cb(grpc_exec_ctx *exec_ctx, void *arg, /*session */ bool success) { session *se = arg; server *sv = se->sv; - grpc_fd_orphan(exec_ctx, se->em_fd, NULL, NULL, "a"); + grpc_fd_orphan(exec_ctx, se->em_fd, NULL, NULL, false /* already_closed */, + "a"); gpr_free(se); /* Start to shutdown listen fd. */ grpc_fd_shutdown(exec_ctx, sv->em_fd, @@ -171,7 +172,8 @@ static void listen_shutdown_cb(grpc_exec_ctx *exec_ctx, void *arg /*server */, int success) { server *sv = arg; - grpc_fd_orphan(exec_ctx, sv->em_fd, NULL, NULL, "b"); + grpc_fd_orphan(exec_ctx, sv->em_fd, NULL, NULL, false /* already_closed */, + "b"); gpr_mu_lock(g_mu); sv->done = 1; @@ -291,7 +293,8 @@ static void client_init(client *cl) { static void client_session_shutdown_cb(grpc_exec_ctx *exec_ctx, void *arg /*client */, int success) { client *cl = arg; - grpc_fd_orphan(exec_ctx, cl->em_fd, NULL, NULL, "c"); + grpc_fd_orphan(exec_ctx, cl->em_fd, NULL, NULL, false /* already_closed */, + "c"); cl->done = 1; GPR_ASSERT( GRPC_LOG_IF_ERROR("pollset_kick", grpc_pollset_kick(g_pollset, NULL))); @@ -511,7 +514,7 @@ static void test_grpc_fd_change(void) { GPR_ASSERT(b.cb_that_ran == second_read_callback); gpr_mu_unlock(g_mu); - grpc_fd_orphan(&exec_ctx, em_fd, NULL, NULL, "d"); + grpc_fd_orphan(&exec_ctx, em_fd, NULL, NULL, false /* already_closed */, "d"); grpc_exec_ctx_finish(&exec_ctx); destroy_change_data(&a); destroy_change_data(&b); diff --git a/test/core/iomgr/pollset_set_test.c b/test/core/iomgr/pollset_set_test.c index 6aedaf1081a..5750ac0f4b3 100644 --- a/test/core/iomgr/pollset_set_test.c +++ b/test/core/iomgr/pollset_set_test.c @@ -137,7 +137,8 @@ static void cleanup_test_fds(grpc_exec_ctx *exec_ctx, test_fd *tfds, * grpc_wakeup_fd and we would like to destroy it ourselves (by calling * grpc_wakeup_fd_destroy). To prevent grpc_fd from calling close() on the * underlying fd, call it with a non-NULL 'release_fd' parameter */ - grpc_fd_orphan(exec_ctx, tfds[i].fd, NULL, &release_fd, "test_fd_cleanup"); + grpc_fd_orphan(exec_ctx, tfds[i].fd, NULL, &release_fd, + false /* already_closed */, "test_fd_cleanup"); grpc_exec_ctx_flush(exec_ctx); grpc_wakeup_fd_destroy(&tfds[i].wakeup_fd); From 9968c253cda0b039c7bae6afb9ac29d74b63bc9b Mon Sep 17 00:00:00 2001 From: Yuchen Zeng Date: Thu, 13 Jul 2017 14:55:40 -0700 Subject: [PATCH 034/127] Update bm_pollset with the fd_orphan change --- test/cpp/microbenchmarks/bm_pollset.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/cpp/microbenchmarks/bm_pollset.cc b/test/cpp/microbenchmarks/bm_pollset.cc index 683f4703c2a..1fc1f2f83b1 100644 --- a/test/cpp/microbenchmarks/bm_pollset.cc +++ b/test/cpp/microbenchmarks/bm_pollset.cc @@ -149,7 +149,7 @@ static void BM_PollAddFd(benchmark::State& state) { grpc_pollset_add_fd(&exec_ctx, ps, fd); grpc_exec_ctx_flush(&exec_ctx); } - grpc_fd_orphan(&exec_ctx, fd, NULL, NULL, "xxx"); + grpc_fd_orphan(&exec_ctx, fd, NULL, NULL, false /* already_closed */, "xxx"); grpc_closure shutdown_ps_closure; GRPC_CLOSURE_INIT(&shutdown_ps_closure, shutdown_ps, ps, grpc_schedule_on_exec_ctx); @@ -247,7 +247,8 @@ static void BM_SingleThreadPollOneFd(benchmark::State& state) { while (!done) { GRPC_ERROR_UNREF(grpc_pollset_work(&exec_ctx, ps, NULL, now, deadline)); } - grpc_fd_orphan(&exec_ctx, wakeup, NULL, NULL, "done"); + grpc_fd_orphan(&exec_ctx, wakeup, NULL, NULL, false /* already_closed */, + "done"); wakeup_fd.read_fd = 0; grpc_closure shutdown_ps_closure; GRPC_CLOSURE_INIT(&shutdown_ps_closure, shutdown_ps, ps, From 104dd1fba73f303add4f19900b0eb41b0a450c70 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Tue, 18 Jul 2017 12:36:29 -0700 Subject: [PATCH 035/127] Fix umbrella header of BoringSSL --- src/objective-c/BoringSSL.podspec | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/objective-c/BoringSSL.podspec b/src/objective-c/BoringSSL.podspec index 81e6555cfd2..37798ec3c6b 100644 --- a/src/objective-c/BoringSSL.podspec +++ b/src/objective-c/BoringSSL.podspec @@ -167,7 +167,6 @@ Pod::Spec.new do |s| #include "hkdf.h" #include "md4.h" #include "md5.h" - #include "newhope.h" #include "obj_mac.h" #include "objects.h" #include "opensslv.h" @@ -181,7 +180,6 @@ Pod::Spec.new do |s| #include "ripemd.h" #include "safestack.h" #include "srtp.h" - #include "time_support.h" #include "x509.h" #include "x509v3.h" EOF From 87116f449985cd49728326ecbdb7293cc522b8ff Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 12 Jul 2017 14:22:46 -0700 Subject: [PATCH 036/127] Fix failures in libuv portability tests --- src/core/lib/iomgr/iomgr_uv.c | 4 + src/core/lib/iomgr/resolve_address_uv.c | 17 ++-- src/core/lib/iomgr/tcp_server_uv.c | 109 ++++++++++++++++-------- src/core/lib/iomgr/tcp_uv.c | 4 + 4 files changed, 91 insertions(+), 43 deletions(-) diff --git a/src/core/lib/iomgr/iomgr_uv.c b/src/core/lib/iomgr/iomgr_uv.c index 49d1a03c322..7a99a6efdd3 100644 --- a/src/core/lib/iomgr/iomgr_uv.c +++ b/src/core/lib/iomgr/iomgr_uv.c @@ -21,12 +21,16 @@ #ifdef GRPC_UV #include "src/core/lib/debug/trace.h" +#include "src/core/lib/iomgr/executor.h" #include "src/core/lib/iomgr/pollset_uv.h" #include "src/core/lib/iomgr/tcp_uv.h" void grpc_iomgr_platform_init(void) { + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_pollset_global_init(); grpc_register_tracer("tcp", &grpc_tcp_trace); + grpc_executor_set_threading(&exec_ctx, false); + grpc_exec_ctx_finish(&exec_ctx); } void grpc_iomgr_platform_flush(void) {} void grpc_iomgr_platform_shutdown(void) { grpc_pollset_global_shutdown(); } diff --git a/src/core/lib/iomgr/resolve_address_uv.c b/src/core/lib/iomgr/resolve_address_uv.c index a98b8e62db3..5180357cb16 100644 --- a/src/core/lib/iomgr/resolve_address_uv.c +++ b/src/core/lib/iomgr/resolve_address_uv.c @@ -114,11 +114,14 @@ static void getaddrinfo_callback(uv_getaddrinfo_t *req, int status, grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_error *error; int retry_status; + char *port = r->port; gpr_free(req); retry_status = retry_named_port_failure(status, r, getaddrinfo_callback); if (retry_status == 0) { - // The request is being retried. Nothing should be done here + /* The request is being retried. It is using its own port string, so we free + * the original one */ + gpr_free(port); return; } /* Either no retry was attempted, or the retry failed. Either way, the @@ -218,16 +221,18 @@ static void resolve_address_impl(grpc_exec_ctx *exec_ctx, const char *name, grpc_pollset_set *interested_parties, grpc_closure *on_done, grpc_resolved_addresses **addrs) { - uv_getaddrinfo_t *req; - request *r; - struct addrinfo *hints; - char *host; - char *port; + uv_getaddrinfo_t *req = NULL; + request *r = NULL; + struct addrinfo *hints = NULL; + char *host = NULL; + char *port = NULL; grpc_error *err; int s; err = try_split_host_port(name, default_port, &host, &port); if (err != GRPC_ERROR_NONE) { GRPC_CLOSURE_SCHED(exec_ctx, on_done, err); + gpr_free(host); + gpr_free(port); return; } r = gpr_malloc(sizeof(request)); diff --git a/src/core/lib/iomgr/tcp_server_uv.c b/src/core/lib/iomgr/tcp_server_uv.c index 2ab836cc34d..a63a36bf587 100644 --- a/src/core/lib/iomgr/tcp_server_uv.c +++ b/src/core/lib/iomgr/tcp_server_uv.c @@ -20,6 +20,7 @@ #ifdef GRPC_UV +#include #include #include @@ -43,6 +44,8 @@ struct grpc_tcp_listener { struct grpc_tcp_listener *next; bool closed; + + bool has_pending_connection; }; struct grpc_tcp_server { @@ -142,10 +145,12 @@ static void handle_close_callback(uv_handle_t *handle) { } static void close_listener(grpc_tcp_listener *sp) { + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; if (!sp->closed) { sp->closed = true; uv_close((uv_handle_t *)sp->handle, handle_close_callback); } + grpc_exec_ctx_finish(&exec_ctx); } static void tcp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) { @@ -183,18 +188,49 @@ void grpc_tcp_server_unref(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) { } } -static void accepted_connection_close_cb(uv_handle_t *handle) { - gpr_free(handle); -} - -static void on_connect(uv_stream_t *server, int status) { - grpc_tcp_listener *sp = (grpc_tcp_listener *)server->data; +static void finish_accept(grpc_exec_ctx *exec_ctx, grpc_tcp_listener *sp) { + grpc_tcp_server_acceptor *acceptor = gpr_malloc(sizeof(*acceptor)); uv_tcp_t *client; grpc_endpoint *ep = NULL; - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_resolved_address peer_name; char *peer_name_string; int err; + uv_tcp_t *server = sp->handle; + + client = gpr_malloc(sizeof(uv_tcp_t)); + uv_tcp_init(uv_default_loop(), client); + // UV documentation says this is guaranteed to succeed + uv_accept((uv_stream_t *)server, (uv_stream_t *)client); + peer_name_string = NULL; + memset(&peer_name, 0, sizeof(grpc_resolved_address)); + peer_name.len = sizeof(struct sockaddr_storage); + err = uv_tcp_getpeername(client, (struct sockaddr *)&peer_name.addr, + (int *)&peer_name.len); + if (err == 0) { + peer_name_string = grpc_sockaddr_to_uri(&peer_name); + } else { + gpr_log(GPR_INFO, "uv_tcp_getpeername error: %s", uv_strerror(err)); + } + if (GRPC_TRACER_ON(grpc_tcp_trace)) { + if (peer_name_string) { + gpr_log(GPR_DEBUG, "SERVER_CONNECT: %p accepted connection: %s", + sp->server, peer_name_string); + } else { + gpr_log(GPR_DEBUG, "SERVER_CONNECT: %p accepted connection", sp->server); + } + } + ep = grpc_tcp_create(client, sp->server->resource_quota, peer_name_string); + acceptor->from_server = sp->server; + acceptor->port_index = sp->port_index; + acceptor->fd_index = 0; + sp->server->on_accept_cb(exec_ctx, sp->server->on_accept_cb_arg, ep, NULL, + acceptor); + gpr_free(peer_name_string); +} + +static void on_connect(uv_stream_t *server, int status) { + grpc_tcp_listener *sp = (grpc_tcp_listener *)server->data; + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; if (status < 0) { switch (status) { @@ -207,35 +243,17 @@ static void on_connect(uv_stream_t *server, int status) { } } - client = gpr_malloc(sizeof(uv_tcp_t)); - uv_tcp_init(uv_default_loop(), client); - // UV documentation says this is guaranteed to succeed - uv_accept((uv_stream_t *)server, (uv_stream_t *)client); - // If the server has not been started, we discard incoming connections - if (sp->server->on_accept_cb == NULL) { - uv_close((uv_handle_t *)client, accepted_connection_close_cb); + GPR_ASSERT(!sp->has_pending_connection); + + gpr_log(GPR_DEBUG, "SERVER_CONNECT: %p incoming connection", sp->server); + + // Create acceptor. + if (sp->server->on_accept_cb) { + finish_accept(&exec_ctx, sp); } else { - peer_name_string = NULL; - memset(&peer_name, 0, sizeof(grpc_resolved_address)); - peer_name.len = sizeof(struct sockaddr_storage); - err = uv_tcp_getpeername(client, (struct sockaddr *)&peer_name.addr, - (int *)&peer_name.len); - if (err == 0) { - peer_name_string = grpc_sockaddr_to_uri(&peer_name); - } else { - gpr_log(GPR_INFO, "uv_tcp_getpeername error: %s", uv_strerror(status)); - } - ep = grpc_tcp_create(client, sp->server->resource_quota, peer_name_string); - // Create acceptor. - grpc_tcp_server_acceptor *acceptor = gpr_malloc(sizeof(*acceptor)); - acceptor->from_server = sp->server; - acceptor->port_index = sp->port_index; - acceptor->fd_index = 0; - sp->server->on_accept_cb(&exec_ctx, sp->server->on_accept_cb_arg, ep, NULL, - acceptor); - grpc_exec_ctx_finish(&exec_ctx); - gpr_free(peer_name_string); + sp->has_pending_connection = true; } + grpc_exec_ctx_finish(&exec_ctx); } static grpc_error *add_socket_to_server(grpc_tcp_server *s, uv_tcp_t *handle, @@ -282,7 +300,7 @@ static grpc_error *add_socket_to_server(grpc_tcp_server *s, uv_tcp_t *handle, GPR_ASSERT(port >= 0); GPR_ASSERT(!s->on_accept_cb && "must add ports before starting server"); - sp = gpr_malloc(sizeof(grpc_tcp_listener)); + sp = gpr_zalloc(sizeof(grpc_tcp_listener)); sp->next = NULL; if (s->head == NULL) { s->head = sp; @@ -366,6 +384,18 @@ grpc_error *grpc_tcp_server_add_port(grpc_tcp_server *s, gpr_free(allocated_addr); + if (GRPC_TRACER_ON(grpc_tcp_trace)) { + char *port_string; + grpc_sockaddr_to_string(&port_string, addr, 0); + const char *str = grpc_error_string(error); + if (port_string) { + gpr_log(GPR_DEBUG, "SERVER %p add_port %s error=%s", s, port_string, str); + gpr_free(port_string); + } else { + gpr_log(GPR_DEBUG, "SERVER %p add_port error=%s", s, str); + } + } + if (error != GRPC_ERROR_NONE) { grpc_error *error_out = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( "Failed to add port to server", &error, 1); @@ -385,13 +415,18 @@ void grpc_tcp_server_start(grpc_exec_ctx *exec_ctx, grpc_tcp_server *server, grpc_tcp_listener *sp; (void)pollsets; (void)pollset_count; + if (GRPC_TRACER_ON(grpc_tcp_trace)) { + gpr_log(GPR_DEBUG, "SERVER_START %p", server); + } GPR_ASSERT(on_accept_cb); GPR_ASSERT(!server->on_accept_cb); server->on_accept_cb = on_accept_cb; server->on_accept_cb_arg = cb_arg; for (sp = server->head; sp; sp = sp->next) { - GPR_ASSERT(uv_listen((uv_stream_t *)sp->handle, SOMAXCONN, on_connect) == - 0); + if (sp->has_pending_connection) { + finish_accept(exec_ctx, sp); + sp->has_pending_connection = false; + } } } diff --git a/src/core/lib/iomgr/tcp_uv.c b/src/core/lib/iomgr/tcp_uv.c index ff5fd3edc85..0302af2a062 100644 --- a/src/core/lib/iomgr/tcp_uv.c +++ b/src/core/lib/iomgr/tcp_uv.c @@ -307,6 +307,10 @@ static void uv_endpoint_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, grpc_error *why) { grpc_tcp *tcp = (grpc_tcp *)ep; if (!tcp->shutting_down) { + if (GRPC_TRACER_ON(grpc_tcp_trace)) { + const char *str = grpc_error_string(why); + gpr_log(GPR_DEBUG, "TCP %p shutdown why=%s", tcp->handle, str); + } tcp->shutting_down = true; uv_shutdown_t *req = &tcp->shutdown_req; uv_shutdown(req, (uv_stream_t *)tcp->handle, shutdown_callback); From b8e07ad780ceb0bae7c431d0de1c6343bf275ceb Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 18 Jul 2017 13:20:55 -0700 Subject: [PATCH 037/127] Add asserts that uv calls all run on the same thread --- BUILD | 1 + build.yaml | 1 + gRPC-Core.podspec | 2 + grpc.gemspec | 1 + package.xml | 1 + src/core/lib/iomgr/iomgr_uv.c | 4 ++ src/core/lib/iomgr/iomgr_uv.h | 37 +++++++++++++++++++ src/core/lib/iomgr/pollset_uv.c | 7 ++++ src/core/lib/iomgr/resolve_address_uv.c | 4 ++ src/core/lib/iomgr/tcp_client_uv.c | 3 ++ src/core/lib/iomgr/tcp_server_uv.c | 6 +++ src/core/lib/iomgr/tcp_uv.c | 3 ++ src/core/lib/iomgr/timer_uv.c | 4 ++ tools/doxygen/Doxyfile.core.internal | 1 + .../generated/sources_and_headers.json | 2 + tools/run_tests/run_tests.py | 2 +- vsprojects/vcxproj/grpc/grpc.vcxproj | 1 + vsprojects/vcxproj/grpc/grpc.vcxproj.filters | 3 ++ .../grpc_test_util/grpc_test_util.vcxproj | 1 + .../grpc_test_util.vcxproj.filters | 3 ++ .../grpc_unsecure/grpc_unsecure.vcxproj | 1 + .../grpc_unsecure.vcxproj.filters | 3 ++ 22 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 src/core/lib/iomgr/iomgr_uv.h diff --git a/BUILD b/BUILD index 495bb668eb1..189a8276e52 100644 --- a/BUILD +++ b/BUILD @@ -597,6 +597,7 @@ grpc_cc_library( "src/core/lib/iomgr/iomgr.h", "src/core/lib/iomgr/iomgr_internal.h", "src/core/lib/iomgr/iomgr_posix.h", + "src/core/lib/iomgr/iomgr_uv.h", "src/core/lib/iomgr/is_epollexclusive_available.h", "src/core/lib/iomgr/load_file.h", "src/core/lib/iomgr/lockfree_event.h", diff --git a/build.yaml b/build.yaml index e55c4ca3012..f43a13e9bcd 100644 --- a/build.yaml +++ b/build.yaml @@ -213,6 +213,7 @@ filegroups: - src/core/lib/iomgr/iomgr.h - src/core/lib/iomgr/iomgr_internal.h - src/core/lib/iomgr/iomgr_posix.h + - src/core/lib/iomgr/iomgr_uv.h - src/core/lib/iomgr/is_epollexclusive_available.h - src/core/lib/iomgr/load_file.h - src/core/lib/iomgr/lockfree_event.h diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec index 3f841d51d8a..7a2c5a40f4f 100644 --- a/gRPC-Core.podspec +++ b/gRPC-Core.podspec @@ -276,6 +276,7 @@ Pod::Spec.new do |s| 'src/core/lib/iomgr/iomgr.h', 'src/core/lib/iomgr/iomgr_internal.h', 'src/core/lib/iomgr/iomgr_posix.h', + 'src/core/lib/iomgr/iomgr_uv.h', 'src/core/lib/iomgr/is_epollexclusive_available.h', 'src/core/lib/iomgr/load_file.h', 'src/core/lib/iomgr/lockfree_event.h', @@ -753,6 +754,7 @@ Pod::Spec.new do |s| 'src/core/lib/iomgr/iomgr.h', 'src/core/lib/iomgr/iomgr_internal.h', 'src/core/lib/iomgr/iomgr_posix.h', + 'src/core/lib/iomgr/iomgr_uv.h', 'src/core/lib/iomgr/is_epollexclusive_available.h', 'src/core/lib/iomgr/load_file.h', 'src/core/lib/iomgr/lockfree_event.h', diff --git a/grpc.gemspec b/grpc.gemspec index 663915b75ea..692977c7400 100755 --- a/grpc.gemspec +++ b/grpc.gemspec @@ -208,6 +208,7 @@ Gem::Specification.new do |s| s.files += %w( src/core/lib/iomgr/iomgr.h ) s.files += %w( src/core/lib/iomgr/iomgr_internal.h ) s.files += %w( src/core/lib/iomgr/iomgr_posix.h ) + s.files += %w( src/core/lib/iomgr/iomgr_uv.h ) s.files += %w( src/core/lib/iomgr/is_epollexclusive_available.h ) s.files += %w( src/core/lib/iomgr/load_file.h ) s.files += %w( src/core/lib/iomgr/lockfree_event.h ) diff --git a/package.xml b/package.xml index cfa45f06d76..0714e614151 100644 --- a/package.xml +++ b/package.xml @@ -222,6 +222,7 @@ + diff --git a/src/core/lib/iomgr/iomgr_uv.c b/src/core/lib/iomgr/iomgr_uv.c index 7a99a6efdd3..c484a39c540 100644 --- a/src/core/lib/iomgr/iomgr_uv.c +++ b/src/core/lib/iomgr/iomgr_uv.c @@ -22,14 +22,18 @@ #include "src/core/lib/debug/trace.h" #include "src/core/lib/iomgr/executor.h" +#include "src/core/lib/iomgr/iomgr_uv.h" #include "src/core/lib/iomgr/pollset_uv.h" #include "src/core/lib/iomgr/tcp_uv.h" +gpr_thd_id grpc_init_thread; + void grpc_iomgr_platform_init(void) { grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_pollset_global_init(); grpc_register_tracer("tcp", &grpc_tcp_trace); grpc_executor_set_threading(&exec_ctx, false); + grpc_init_thread = gpr_thd_currentid(); grpc_exec_ctx_finish(&exec_ctx); } void grpc_iomgr_platform_flush(void) {} diff --git a/src/core/lib/iomgr/iomgr_uv.h b/src/core/lib/iomgr/iomgr_uv.h new file mode 100644 index 00000000000..35c073a0330 --- /dev/null +++ b/src/core/lib/iomgr/iomgr_uv.h @@ -0,0 +1,37 @@ +/* + * + * Copyright 2017 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPC_CORE_LIB_IOMGR_IOMGR_UV_H +#define GRPC_CORE_LIB_IOMGR_IOMGR_UV_H + +#include "src/core/lib/iomgr/iomgr_internal.h" + +#include + +/* The thread ID of the thread on which grpc was initialized. Used to verify + * that all calls into libuv are made on that same thread */ +extern gpr_thd_id grpc_init_thread; + +#ifdef GRPC_UV_THREAD_CHECK +#define GRPC_ASSERT_SAME_THREAD() \ + GPR_ASSERT(gpr_thd_currentid() == grpc_init_thread) +#else +#define GRPC_ASSERT_SAME_THREAD() +#endif /* GRPC_UV_THREAD_CHECK */ + +#endif /* GRPC_CORE_LIB_IOMGR_IOMGR_UV_H */ diff --git a/src/core/lib/iomgr/pollset_uv.c b/src/core/lib/iomgr/pollset_uv.c index 1a54065a914..47c8c79cc2a 100644 --- a/src/core/lib/iomgr/pollset_uv.c +++ b/src/core/lib/iomgr/pollset_uv.c @@ -28,6 +28,7 @@ #include #include +#include "src/core/lib/iomgr/iomgr_uv.h" #include "src/core/lib/iomgr/pollset.h" #include "src/core/lib/iomgr/pollset_uv.h" @@ -69,6 +70,7 @@ void grpc_pollset_global_init(void) { } void grpc_pollset_global_shutdown(void) { + GRPC_ASSERT_SAME_THREAD(); gpr_mu_destroy(&grpc_polling_mu); uv_close((uv_handle_t *)dummy_uv_handle, dummy_handle_close_cb); } @@ -78,6 +80,7 @@ static void timer_run_cb(uv_timer_t *timer) {} static void timer_close_cb(uv_handle_t *handle) { handle->data = (void *)1; } void grpc_pollset_init(grpc_pollset *pollset, gpr_mu **mu) { + GRPC_ASSERT_SAME_THREAD(); *mu = &grpc_polling_mu; uv_timer_init(uv_default_loop(), &pollset->timer); pollset->shutting_down = 0; @@ -86,6 +89,7 @@ void grpc_pollset_init(grpc_pollset *pollset, gpr_mu **mu) { void grpc_pollset_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_closure *closure) { GPR_ASSERT(!pollset->shutting_down); + GRPC_ASSERT_SAME_THREAD(); pollset->shutting_down = 1; if (grpc_pollset_work_run_loop) { // Drain any pending UV callbacks without blocking @@ -98,6 +102,7 @@ void grpc_pollset_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, } void grpc_pollset_destroy(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset) { + GRPC_ASSERT_SAME_THREAD(); uv_close((uv_handle_t *)&pollset->timer, timer_close_cb); // timer.data is a boolean indicating that the timer has finished closing pollset->timer.data = (void *)0; @@ -112,6 +117,7 @@ grpc_error *grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_pollset_worker **worker_hdl, gpr_timespec now, gpr_timespec deadline) { uint64_t timeout; + GRPC_ASSERT_SAME_THREAD(); gpr_mu_unlock(&grpc_polling_mu); if (grpc_pollset_work_run_loop) { if (gpr_time_cmp(deadline, now) >= 0) { @@ -140,6 +146,7 @@ grpc_error *grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_error *grpc_pollset_kick(grpc_pollset *pollset, grpc_pollset_worker *specific_worker) { + GRPC_ASSERT_SAME_THREAD(); uv_timer_start(dummy_uv_handle, dummy_timer_cb, 0, 0); return GRPC_ERROR_NONE; } diff --git a/src/core/lib/iomgr/resolve_address_uv.c b/src/core/lib/iomgr/resolve_address_uv.c index 5180357cb16..f910ec26b26 100644 --- a/src/core/lib/iomgr/resolve_address_uv.c +++ b/src/core/lib/iomgr/resolve_address_uv.c @@ -30,6 +30,7 @@ #include "src/core/lib/iomgr/closure.h" #include "src/core/lib/iomgr/error.h" #include "src/core/lib/iomgr/exec_ctx.h" +#include "src/core/lib/iomgr/iomgr_uv.h" #include "src/core/lib/iomgr/resolve_address.h" #include "src/core/lib/iomgr/sockaddr.h" #include "src/core/lib/iomgr/sockaddr_utils.h" @@ -174,6 +175,8 @@ static grpc_error *blocking_resolve_address_impl( grpc_error *err; int retry_status; + GRPC_ASSERT_SAME_THREAD(); + req.addrinfo = NULL; err = try_split_host_port(name, default_port, &host, &port); @@ -228,6 +231,7 @@ static void resolve_address_impl(grpc_exec_ctx *exec_ctx, const char *name, char *port = NULL; grpc_error *err; int s; + GRPC_ASSERT_SAME_THREAD(); err = try_split_host_port(name, default_port, &host, &port); if (err != GRPC_ERROR_NONE) { GRPC_CLOSURE_SCHED(exec_ctx, on_done, err); diff --git a/src/core/lib/iomgr/tcp_client_uv.c b/src/core/lib/iomgr/tcp_client_uv.c index 2f1d237c07b..098ff7648de 100644 --- a/src/core/lib/iomgr/tcp_client_uv.c +++ b/src/core/lib/iomgr/tcp_client_uv.c @@ -26,6 +26,7 @@ #include #include "src/core/lib/iomgr/error.h" +#include "src/core/lib/iomgr/iomgr_uv.h" #include "src/core/lib/iomgr/sockaddr_utils.h" #include "src/core/lib/iomgr/tcp_client.h" #include "src/core/lib/iomgr/tcp_uv.h" @@ -124,6 +125,8 @@ static void tcp_client_connect_impl(grpc_exec_ctx *exec_ctx, (void)channel_args; (void)interested_parties; + GRPC_ASSERT_SAME_THREAD(); + if (channel_args != NULL) { for (size_t i = 0; i < channel_args->num_args; i++) { if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_RESOURCE_QUOTA)) { diff --git a/src/core/lib/iomgr/tcp_server_uv.c b/src/core/lib/iomgr/tcp_server_uv.c index a63a36bf587..7b45e08c9b8 100644 --- a/src/core/lib/iomgr/tcp_server_uv.c +++ b/src/core/lib/iomgr/tcp_server_uv.c @@ -28,6 +28,7 @@ #include "src/core/lib/iomgr/error.h" #include "src/core/lib/iomgr/exec_ctx.h" +#include "src/core/lib/iomgr/iomgr_uv.h" #include "src/core/lib/iomgr/sockaddr.h" #include "src/core/lib/iomgr/sockaddr_utils.h" #include "src/core/lib/iomgr/tcp_server.h" @@ -107,6 +108,7 @@ grpc_error *grpc_tcp_server_create(grpc_exec_ctx *exec_ctx, } grpc_tcp_server *grpc_tcp_server_ref(grpc_tcp_server *s) { + GRPC_ASSERT_SAME_THREAD(); gpr_ref(&s->refs); return s; } @@ -173,6 +175,7 @@ static void tcp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) { } void grpc_tcp_server_unref(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) { + GRPC_ASSERT_SAME_THREAD(); if (gpr_unref(&s->refs)) { /* Complete shutdown_starting work before destroying. */ grpc_exec_ctx local_exec_ctx = GRPC_EXEC_CTX_INIT; @@ -335,6 +338,8 @@ grpc_error *grpc_tcp_server_add_port(grpc_tcp_server *s, int status; grpc_error *error = GRPC_ERROR_NONE; + GRPC_ASSERT_SAME_THREAD(); + if (s->tail != NULL) { port_index = s->tail->port_index + 1; } @@ -415,6 +420,7 @@ void grpc_tcp_server_start(grpc_exec_ctx *exec_ctx, grpc_tcp_server *server, grpc_tcp_listener *sp; (void)pollsets; (void)pollset_count; + GRPC_ASSERT_SAME_THREAD(); if (GRPC_TRACER_ON(grpc_tcp_trace)) { gpr_log(GPR_DEBUG, "SERVER_START %p", server); } diff --git a/src/core/lib/iomgr/tcp_uv.c b/src/core/lib/iomgr/tcp_uv.c index 0302af2a062..115297634b1 100644 --- a/src/core/lib/iomgr/tcp_uv.c +++ b/src/core/lib/iomgr/tcp_uv.c @@ -30,6 +30,7 @@ #include #include "src/core/lib/iomgr/error.h" +#include "src/core/lib/iomgr/iomgr_uv.h" #include "src/core/lib/iomgr/network_status_tracker.h" #include "src/core/lib/iomgr/resource_quota.h" #include "src/core/lib/iomgr/tcp_uv.h" @@ -183,6 +184,7 @@ static void uv_endpoint_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, grpc_tcp *tcp = (grpc_tcp *)ep; int status; grpc_error *error = GRPC_ERROR_NONE; + GRPC_ASSERT_SAME_THREAD(); GPR_ASSERT(tcp->read_cb == NULL); tcp->read_cb = cb; tcp->read_slices = read_slices; @@ -236,6 +238,7 @@ static void uv_endpoint_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, unsigned int i; grpc_slice *slice; uv_write_t *write_req; + GRPC_ASSERT_SAME_THREAD(); if (GRPC_TRACER_ON(grpc_tcp_trace)) { size_t j; diff --git a/src/core/lib/iomgr/timer_uv.c b/src/core/lib/iomgr/timer_uv.c index 4f204cfbf8c..e004ff5a3a4 100644 --- a/src/core/lib/iomgr/timer_uv.c +++ b/src/core/lib/iomgr/timer_uv.c @@ -24,6 +24,7 @@ #include #include "src/core/lib/debug/trace.h" +#include "src/core/lib/iomgr/iomgr_uv.h" #include "src/core/lib/iomgr/timer.h" #include @@ -42,6 +43,7 @@ static void stop_uv_timer(uv_timer_t *handle) { void run_expired_timer(uv_timer_t *handle) { grpc_timer *timer = (grpc_timer *)handle->data; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + GRPC_ASSERT_SAME_THREAD(); GPR_ASSERT(timer->pending); timer->pending = 0; GRPC_CLOSURE_SCHED(&exec_ctx, timer->closure, GRPC_ERROR_NONE); @@ -54,6 +56,7 @@ void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer, gpr_timespec now) { uint64_t timeout; uv_timer_t *uv_timer; + GRPC_ASSERT_SAME_THREAD(); timer->closure = closure; if (gpr_time_cmp(deadline, now) <= 0) { timer->pending = 0; @@ -74,6 +77,7 @@ void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer, } void grpc_timer_cancel(grpc_exec_ctx *exec_ctx, grpc_timer *timer) { + GRPC_ASSERT_SAME_THREAD(); if (timer->pending) { timer->pending = 0; GRPC_CLOSURE_SCHED(exec_ctx, timer->closure, GRPC_ERROR_CANCELLED); diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal index 766c20f59b7..1263bdbb743 100644 --- a/tools/doxygen/Doxyfile.core.internal +++ b/tools/doxygen/Doxyfile.core.internal @@ -1118,6 +1118,7 @@ src/core/lib/iomgr/iomgr_internal.h \ src/core/lib/iomgr/iomgr_posix.c \ src/core/lib/iomgr/iomgr_posix.h \ src/core/lib/iomgr/iomgr_uv.c \ +src/core/lib/iomgr/iomgr_uv.h \ src/core/lib/iomgr/iomgr_windows.c \ src/core/lib/iomgr/is_epollexclusive_available.c \ src/core/lib/iomgr/is_epollexclusive_available.h \ diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json index 477a258daa6..93411a8c614 100644 --- a/tools/run_tests/generated/sources_and_headers.json +++ b/tools/run_tests/generated/sources_and_headers.json @@ -7654,6 +7654,7 @@ "src/core/lib/iomgr/iomgr.h", "src/core/lib/iomgr/iomgr_internal.h", "src/core/lib/iomgr/iomgr_posix.h", + "src/core/lib/iomgr/iomgr_uv.h", "src/core/lib/iomgr/is_epollexclusive_available.h", "src/core/lib/iomgr/load_file.h", "src/core/lib/iomgr/lockfree_event.h", @@ -7812,6 +7813,7 @@ "src/core/lib/iomgr/iomgr_posix.c", "src/core/lib/iomgr/iomgr_posix.h", "src/core/lib/iomgr/iomgr_uv.c", + "src/core/lib/iomgr/iomgr_uv.h", "src/core/lib/iomgr/iomgr_windows.c", "src/core/lib/iomgr/is_epollexclusive_available.c", "src/core/lib/iomgr/is_epollexclusive_available.h", diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py index 611868ce5a4..50eed6256c9 100755 --- a/tools/run_tests/run_tests.py +++ b/tools/run_tests/run_tests.py @@ -245,7 +245,7 @@ class CLanguage(object): self._docker_distro, self._make_options = self._compiler_options(self.args.use_docker, self.args.compiler) if args.iomgr_platform == "uv": - cflags = '-DGRPC_UV ' + cflags = '-DGRPC_UV -DGRPC_UV_THREAD_CHECK' try: cflags += subprocess.check_output(['pkg-config', '--cflags', 'libuv']).strip() + ' ' except (subprocess.CalledProcessError, OSError): diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj b/vsprojects/vcxproj/grpc/grpc.vcxproj index f9badbbd353..12cb39a3df6 100644 --- a/vsprojects/vcxproj/grpc/grpc.vcxproj +++ b/vsprojects/vcxproj/grpc/grpc.vcxproj @@ -333,6 +333,7 @@ + diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters index f3e997e4e0e..c762200a008 100644 --- a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters +++ b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters @@ -944,6 +944,9 @@ src\core\lib\iomgr + + src\core\lib\iomgr + src\core\lib\iomgr diff --git a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj index 1899be91db3..98bf5aeb69a 100644 --- a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj +++ b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj @@ -228,6 +228,7 @@ + diff --git a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters index 9c81fc5bf51..145b51c206b 100644 --- a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters +++ b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters @@ -677,6 +677,9 @@ src\core\lib\iomgr + + src\core\lib\iomgr + src\core\lib\iomgr diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj index 3a865f3e812..12c352a3f81 100644 --- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj +++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj @@ -323,6 +323,7 @@ + diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters index 0310ebc012c..0b598363b8b 100644 --- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters +++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters @@ -854,6 +854,9 @@ src\core\lib\iomgr + + src\core\lib\iomgr + src\core\lib\iomgr From 79e2d8e89f635e07312d07afcc1f26a49aa48f06 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 18 Jul 2017 13:23:55 -0700 Subject: [PATCH 038/127] libuv tests: skip a test that spawns a thread --- build.yaml | 2 ++ tools/run_tests/generated/tests.json | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/build.yaml b/build.yaml index f43a13e9bcd..c8556c4b455 100644 --- a/build.yaml +++ b/build.yaml @@ -2370,6 +2370,8 @@ targets: - grpc - gpr_test_util - gpr + exclude_iomgrs: + - uv platforms: - linux secure: true diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json index dd812414b9f..5be3cf796bd 100644 --- a/tools/run_tests/generated/tests.json +++ b/tools/run_tests/generated/tests.json @@ -1390,7 +1390,9 @@ ], "cpu_cost": 1.0, "exclude_configs": [], - "exclude_iomgrs": [], + "exclude_iomgrs": [ + "uv" + ], "flaky": false, "gtest": false, "language": "c", From 269d3b4faae39ac4a6be66baa5b5fc9a2efb86df Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 18 Jul 2017 15:09:17 -0700 Subject: [PATCH 039/127] Clang format --- src/core/lib/iomgr/iomgr_uv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/lib/iomgr/iomgr_uv.h b/src/core/lib/iomgr/iomgr_uv.h index 35c073a0330..bd406c34f72 100644 --- a/src/core/lib/iomgr/iomgr_uv.h +++ b/src/core/lib/iomgr/iomgr_uv.h @@ -28,7 +28,7 @@ extern gpr_thd_id grpc_init_thread; #ifdef GRPC_UV_THREAD_CHECK -#define GRPC_ASSERT_SAME_THREAD() \ +#define GRPC_ASSERT_SAME_THREAD() \ GPR_ASSERT(gpr_thd_currentid() == grpc_init_thread) #else #define GRPC_ASSERT_SAME_THREAD() From ae5e83b664c9f05bcdf04df7aad34ed108dbf10b Mon Sep 17 00:00:00 2001 From: David Garcia Quintas Date: Tue, 18 Jul 2017 16:11:00 -0700 Subject: [PATCH 040/127] Free pending grpclb update args --- .../ext/filters/client_channel/lb_policy/grpclb/grpclb.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c index cccc3e871a6..fdb18f687f3 100644 --- a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c +++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c @@ -1705,7 +1705,6 @@ static void lb_on_server_status_received_locked(grpc_exec_ctx *exec_ctx, static void glb_update_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, const grpc_lb_policy_args *args) { glb_lb_policy *glb_policy = (glb_lb_policy *)policy; - if (glb_policy->updating_lb_channel) { if (GRPC_TRACER_ON(grpc_lb_glb_trace)) { gpr_log(GPR_INFO, @@ -1813,9 +1812,11 @@ static void glb_lb_channel_on_connectivity_changed_cb(grpc_exec_ctx *exec_ctx, // lb_on_server_status_received will pick up the cancel and reinit // lb_call. if (glb_policy->pending_update_args != NULL) { - const grpc_lb_policy_args *args = glb_policy->pending_update_args; + grpc_lb_policy_args *args = glb_policy->pending_update_args; glb_policy->pending_update_args = NULL; glb_update_locked(exec_ctx, &glb_policy->base, args); + grpc_channel_args_destroy(exec_ctx, args->args); + gpr_free(args); } } else if (glb_policy->started_picking && !glb_policy->shutting_down) { if (glb_policy->retry_timer_active) { From 0d8431afe1d5cf5ede4bad037ba2031586a8fe6c Mon Sep 17 00:00:00 2001 From: Sree Kuchibhotla Date: Tue, 18 Jul 2017 16:21:54 -0700 Subject: [PATCH 041/127] Add/update comments and remove unused fields --- src/core/lib/iomgr/ev_epoll1_linux.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/core/lib/iomgr/ev_epoll1_linux.c b/src/core/lib/iomgr/ev_epoll1_linux.c index dfe2d143a50..f579b16fa58 100644 --- a/src/core/lib/iomgr/ev_epoll1_linux.c +++ b/src/core/lib/iomgr/ev_epoll1_linux.c @@ -120,10 +120,15 @@ struct grpc_pollset { bool reassigning_neighbourhood; grpc_pollset_worker *root_worker; bool kicked_without_poller; + + /* Set to true if the pollset is observed to have no workers available to + * poll */ bool seen_inactive; - bool shutting_down; /* Is the pollset shutting down ? */ - bool finish_shutdown_called; /* Is the 'finish_shutdown_locked()' called ? */ + bool shutting_down; /* Is the pollset shutting down ? */ grpc_closure *shutdown_closure; /* Called after after shutdown is complete */ + + /* Number of workers who are *about-to* attach themselves to the pollset + * worker list */ int begin_refs; grpc_pollset *next; @@ -294,12 +299,6 @@ static void fd_notify_on_write(grpc_exec_ctx *exec_ctx, grpc_fd *fd, static void fd_become_readable(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_pollset *notifier) { grpc_lfev_set_ready(exec_ctx, &fd->read_closure, "read"); - - /* Note, it is possible that fd_become_readable might be called twice with - different 'notifier's when an fd becomes readable and it is in two epoll - sets (This can happen briefly during polling island merges). In such cases - it does not really matter which notifer is set as the read_notifier_pollset - (They would both point to the same polling island anyway) */ /* Use release store to match with acquire load in fd_get_read_notifier */ gpr_atm_rel_store(&fd->read_notifier_pollset, (gpr_atm)notifier); } @@ -442,13 +441,16 @@ static grpc_error *pollset_kick_all(grpc_pollset *pollset) { case DESIGNATED_POLLER: SET_KICK_STATE(worker, KICKED); append_error(&error, grpc_wakeup_fd_wakeup(&global_wakeup_fd), - "pollset_shutdown"); + "pollset_kick_all"); break; } worker = worker->next; } while (worker != pollset->root_worker); } + // TODO: sreek. Check if we need to set 'kicked_without_poller' to true here + // in the else case + return error; } @@ -577,6 +579,11 @@ static bool begin_worker(grpc_pollset *pollset, grpc_pollset_worker *worker, pollset->seen_inactive = false; if (neighbourhood->active_root == NULL) { neighbourhood->active_root = pollset->next = pollset->prev = pollset; + /* TODO: sreek. Why would this worker state be other than UNKICKED + * here ? (since the worker isn't added to the pollset yet, there is no + * way it can be "found" by other threads to get kicked). */ + + /* If there is no designated poller, make this the designated poller */ if (worker->kick_state == UNKICKED && gpr_atm_no_barrier_cas(&g_active_poller, 0, (gpr_atm)worker)) { SET_KICK_STATE(worker, DESIGNATED_POLLER); @@ -605,8 +612,11 @@ static bool begin_worker(grpc_pollset *pollset, grpc_pollset_worker *worker, pollset, worker, kick_state_string(worker->kick_state), pollset->shutting_down); } + if (gpr_cv_wait(&worker->cv, &pollset->mu, deadline) && worker->kick_state == UNKICKED) { + /* If gpr_cv_wait returns true (i.e a timeout), pretend that the worker + received a kick */ SET_KICK_STATE(worker, KICKED); } } From bbd348c5e18794b0fee65a752bc101cdde4b247d Mon Sep 17 00:00:00 2001 From: Yong Ni Date: Tue, 18 Jul 2017 08:38:11 -0700 Subject: [PATCH 042/127] Added all previous minor releases of gRPC to the matrix. Modified the testsuite name format for better display test results in sponge. --- tools/interop_matrix/client_matrix.py | 26 ++++++++++++++++--- .../run_interop_matrix_tests.py | 2 +- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/tools/interop_matrix/client_matrix.py b/tools/interop_matrix/client_matrix.py index 4394e32c085..4d1b5f01695 100644 --- a/tools/interop_matrix/client_matrix.py +++ b/tools/interop_matrix/client_matrix.py @@ -30,9 +30,27 @@ LANG_RUNTIME_MATRIX = { } # Dictionary of releases per language. For each language, we need to provide -# a tuple of release tag (used as the tag for the GCR image) and also github hash. +# a release tag pointing to the latest build of the branch. LANG_RELEASE_MATRIX = { - 'cxx': ['v1.0.1', 'v1.1.2'], - 'go': ['v1.0.1-GA', 'v1.3.0'], - 'java': ['v1.0.3', 'v1.1.2'], + 'cxx': [ + 'v1.0.1', + 'v1.1.4', + 'v1.2.5', + 'v1.3.9', + 'v1.4.2', + ], + 'go': [ + 'v1.0.5', + 'v1.2.1', + 'v1.3.0', + 'v1.4.2', + ], + 'java': [ + 'v1.0.3', + 'v1.1.2', + 'v1.2.0', + 'v1.3.1', + 'v1.4.0', + 'v1.5.0', + ], } diff --git a/tools/interop_matrix/run_interop_matrix_tests.py b/tools/interop_matrix/run_interop_matrix_tests.py index 28126ddf5cc..4315c8277df 100755 --- a/tools/interop_matrix/run_interop_matrix_tests.py +++ b/tools/interop_matrix/run_interop_matrix_tests.py @@ -168,7 +168,7 @@ def run_tests_for_lang(lang, runtime, images): _xml_report_tree, resultset, 'grpc_interop_matrix', - '%s__%s:%s'%(lang,runtime,release), + '%s__%s %s'%(lang,runtime,release), str(uuid.uuid4())) _docker_images_cleanup = [] From 85fac6df5711b418fabc87680d304e25171515f8 Mon Sep 17 00:00:00 2001 From: ncteisen Date: Wed, 12 Jul 2017 07:49:45 -0700 Subject: [PATCH 043/127] Quiet down server builder --- src/cpp/server/server_builder.cc | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/cpp/server/server_builder.cc b/src/cpp/server/server_builder.cc index c90f96c0b72..fa3b9cf7660 100644 --- a/src/cpp/server/server_builder.cc +++ b/src/cpp/server/server_builder.cc @@ -250,13 +250,6 @@ std::unique_ptr ServerBuilder::BuildAndStart() { has_sync_methods && num_frequently_polled_cqs > 0; if (has_sync_methods) { - // This is a Sync server - gpr_log(GPR_INFO, - "Synchronous server. Num CQs: %d, Min pollers: %d, Max Pollers: " - "%d, CQ timeout (msec): %d", - sync_server_settings_.num_cqs, sync_server_settings_.min_pollers, - sync_server_settings_.max_pollers, - sync_server_settings_.cq_timeout_msec); grpc_cq_polling_type polling_type = is_hybrid_server ? GRPC_CQ_NON_POLLING : GRPC_CQ_DEFAULT_POLLING; @@ -272,6 +265,16 @@ std::unique_ptr ServerBuilder::BuildAndStart() { sync_server_settings_.min_pollers, sync_server_settings_.max_pollers, sync_server_settings_.cq_timeout_msec)); + if (has_sync_methods) { + // This is a Sync server + gpr_log(GPR_INFO, + "Synchronous server. Num CQs: %d, Min pollers: %d, Max Pollers: " + "%d, CQ timeout (msec): %d", + sync_server_settings_.num_cqs, sync_server_settings_.min_pollers, + sync_server_settings_.max_pollers, + sync_server_settings_.cq_timeout_msec); + } + ServerInitializer* initializer = server->initializer(); // Register all the completion queues with the server. i.e From 79764a3bfbdec89b93b2f4a52b73e4b2ec275226 Mon Sep 17 00:00:00 2001 From: ncteisen Date: Wed, 12 Jul 2017 07:50:09 -0700 Subject: [PATCH 044/127] Quiet down getenv --- src/core/lib/support/env.h | 2 ++ src/core/lib/support/env_linux.c | 35 +++++++++++++++++++----------- src/core/lib/support/env_posix.c | 5 +++++ src/core/lib/support/env_windows.c | 5 +++++ src/core/lib/support/log.c | 9 +++++++- 5 files changed, 42 insertions(+), 14 deletions(-) diff --git a/src/core/lib/support/env.h b/src/core/lib/support/env.h index 18bc08ac62a..392fcb6e4c0 100644 --- a/src/core/lib/support/env.h +++ b/src/core/lib/support/env.h @@ -36,6 +36,8 @@ char *gpr_getenv(const char *name); /* Sets the the environment with the specified name to the specified value. */ void gpr_setenv(const char *name, const char *value); +char *gpr_getenv_silent(const char *name, char** dst); + #ifdef __cplusplus } #endif diff --git a/src/core/lib/support/env_linux.c b/src/core/lib/support/env_linux.c index 0c79a2c4014..bc488e1b063 100644 --- a/src/core/lib/support/env_linux.c +++ b/src/core/lib/support/env_linux.c @@ -38,8 +38,10 @@ #include "src/core/lib/support/string.h" -char *gpr_getenv(const char *name) { -#if defined(GPR_BACKWARDS_COMPATIBILITY_MODE) +char *gpr_getenv_silent(const char *name, char** dst) { + char* insecure_func_used = NULL; + char* result = NULL; + #if defined(GPR_BACKWARDS_COMPATIBILITY_MODE) typedef char *(*getenv_type)(const char *); static getenv_type getenv_func = NULL; /* Check to see which getenv variant is supported (go from most @@ -48,22 +50,29 @@ char *gpr_getenv(const char *name) { for (size_t i = 0; getenv_func == NULL && i < GPR_ARRAY_SIZE(names); i++) { getenv_func = (getenv_type)dlsym(RTLD_DEFAULT, names[i]); if (getenv_func != NULL && strstr(names[i], "secure") == NULL) { - gpr_log(GPR_DEBUG, - "Warning: insecure environment read function '%s' used", - names[i]); + insecure_func_used = names[i]; } } - char *result = getenv_func(name); - return result == NULL ? result : gpr_strdup(result); + result = getenv_func(name); #elif __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 17) - char *result = secure_getenv(name); - return result == NULL ? result : gpr_strdup(result); + result = secure_getenv(name); #else - gpr_log(GPR_DEBUG, "Warning: insecure environment read function '%s' used", - "getenv"); - char *result = getenv(name); - return result == NULL ? result : gpr_strdup(result); + result = getenv(name); + insecure_func_used = "getenv"; #endif + *dst = result == NULL ? result : gpr_strdup(result); + return insecure_func_used; +} + +char *gpr_getenv(const char *name) { + char* result = NULL; + char* insecure_func_used = gpr_getenv_silent(name, &result); + if (insecure_func_used != NULL) { + gpr_log(GPR_DEBUG, + "Warning: insecure environment read function '%s' used", + insecure_func_used); + } + return result; } void gpr_setenv(const char *name, const char *value) { diff --git a/src/core/lib/support/env_posix.c b/src/core/lib/support/env_posix.c index bdbc4da95a5..8cc802ef883 100644 --- a/src/core/lib/support/env_posix.c +++ b/src/core/lib/support/env_posix.c @@ -29,6 +29,11 @@ #include #include "src/core/lib/support/string.h" +char *gpr_getenv_silent(const char *name, char **dst) { + *dst = gpr_getenv(name); + return NULL; +} + char *gpr_getenv(const char *name) { char *result = getenv(name); return result == NULL ? result : gpr_strdup(result); diff --git a/src/core/lib/support/env_windows.c b/src/core/lib/support/env_windows.c index c1d557e2199..557d5d6ad50 100644 --- a/src/core/lib/support/env_windows.c +++ b/src/core/lib/support/env_windows.c @@ -30,6 +30,11 @@ #include #include +char *gpr_getenv_silent(const char *name, char **dst) { + *dst = gpr_getenv(name); + return NULL; +} + char *gpr_getenv(const char *name) { char *result = NULL; DWORD size; diff --git a/src/core/lib/support/log.c b/src/core/lib/support/log.c index bcc336b8ae7..010dc65d6ae 100644 --- a/src/core/lib/support/log.c +++ b/src/core/lib/support/log.c @@ -64,7 +64,8 @@ void gpr_set_log_verbosity(gpr_log_severity min_severity_to_print) { } void gpr_log_verbosity_init() { - char *verbosity = gpr_getenv("GRPC_VERBOSITY"); + char *verbosity = NULL; + char *insecure_getenv = gpr_getenv_silent("GRPC_VERBOSITY", &verbosity); gpr_atm min_severity_to_print = GPR_LOG_SEVERITY_ERROR; if (verbosity != NULL) { @@ -81,6 +82,12 @@ void gpr_log_verbosity_init() { GPR_LOG_VERBOSITY_UNSET) { gpr_atm_no_barrier_store(&g_min_severity_to_print, min_severity_to_print); } + + if (insecure_getenv != NULL) { + gpr_log(GPR_DEBUG, + "Warning: insecure environment read function '%s' used", + insecure_getenv); + } } void gpr_set_log_function(gpr_log_func f) { From 68d78c6330664019abaefa6e762caf50b93c989d Mon Sep 17 00:00:00 2001 From: ncteisen Date: Thu, 13 Jul 2017 07:25:40 -0700 Subject: [PATCH 045/127] Add comment --- src/core/lib/support/env.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/core/lib/support/env.h b/src/core/lib/support/env.h index 392fcb6e4c0..e1c3bdc66a3 100644 --- a/src/core/lib/support/env.h +++ b/src/core/lib/support/env.h @@ -36,6 +36,10 @@ char *gpr_getenv(const char *name); /* Sets the the environment with the specified name to the specified value. */ void gpr_setenv(const char *name, const char *value); +/* This is a version of gpr_getenv that does not produce any output if it has to + use an insecure version of the function. It is ONLY to be used to solve the + problem in which we need to check an env variable to configure the verbosity + level of logging. So DO NOT USE THIS. */ char *gpr_getenv_silent(const char *name, char** dst); #ifdef __cplusplus From b9b376ccd484b711d32dbffe748bef0f04f8bfa3 Mon Sep 17 00:00:00 2001 From: ncteisen Date: Thu, 13 Jul 2017 07:30:15 -0700 Subject: [PATCH 046/127] Ban the silent version --- tools/run_tests/sanity/core_banned_functions.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/run_tests/sanity/core_banned_functions.py b/tools/run_tests/sanity/core_banned_functions.py index b394bbbeaf1..1f139054847 100755 --- a/tools/run_tests/sanity/core_banned_functions.py +++ b/tools/run_tests/sanity/core_banned_functions.py @@ -41,6 +41,8 @@ BANNED_EXCEPT = { 'grpc_closure_sched(' : ['src/core/lib/iomgr/closure.c'], 'grpc_closure_run(' : ['src/core/lib/iomgr/closure.c'], 'grpc_closure_list_sched(' : ['src/core/lib/iomgr/closure.c'], + 'gpr_getenv_silent(' : ['src/core/lib/support/log.c', 'src/core/lib/support/env_linux.c', + 'src/core/lib/support/env_posix.c', 'src/core/lib/support/env_windows.c'], } errors = 0 From 30939f88548a7318cac2642d6149f651c09f931a Mon Sep 17 00:00:00 2001 From: ncteisen Date: Wed, 5 Jul 2017 15:43:18 -0700 Subject: [PATCH 047/127] Make CreateThreadPool settable --- src/cpp/client/secure_credentials.cc | 2 +- src/cpp/server/create_default_thread_pool.cc | 12 +++++++++++- src/cpp/server/secure_server_credentials.h | 2 +- src/cpp/server/thread_pool_interface.h | 6 +++++- 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/cpp/client/secure_credentials.cc b/src/cpp/client/secure_credentials.cc index 057a058a3fb..0eefd0645b4 100644 --- a/src/cpp/client/secure_credentials.cc +++ b/src/cpp/client/secure_credentials.cc @@ -207,7 +207,7 @@ void MetadataCredentialsPluginWrapper::InvokePlugin( MetadataCredentialsPluginWrapper::MetadataCredentialsPluginWrapper( std::unique_ptr plugin) - : thread_pool_(CreateDefaultThreadPool()), plugin_(std::move(plugin)) {} + : thread_pool_(CreateThreadPool()), plugin_(std::move(plugin)) {} std::shared_ptr MetadataCredentialsFromPlugin( std::unique_ptr plugin) { diff --git a/src/cpp/server/create_default_thread_pool.cc b/src/cpp/server/create_default_thread_pool.cc index 17ad331c9c0..bf76303b454 100644 --- a/src/cpp/server/create_default_thread_pool.cc +++ b/src/cpp/server/create_default_thread_pool.cc @@ -24,12 +24,22 @@ namespace grpc { -ThreadPoolInterface* CreateDefaultThreadPool() { +static ThreadPoolInterface* CreateDefaultThreadPool() { int cores = gpr_cpu_num_cores(); if (!cores) cores = 4; return new DynamicThreadPool(cores); } +static CreateThreadPoolFunc g_ctp_impl = CreateDefaultThreadPool; + +ThreadPoolInterface* CreateThreadPool() { + return g_ctp_impl(); +} + +void SetCreateThreadPool(CreateThreadPoolFunc func) { + g_ctp_impl = func; +} + } // namespace grpc #endif // !GRPC_CUSTOM_DEFAULT_THREAD_POOL diff --git a/src/cpp/server/secure_server_credentials.h b/src/cpp/server/secure_server_credentials.h index 212f0d1df3b..30ee1c7a366 100644 --- a/src/cpp/server/secure_server_credentials.h +++ b/src/cpp/server/secure_server_credentials.h @@ -39,7 +39,7 @@ class AuthMetadataProcessorAyncWrapper final { AuthMetadataProcessorAyncWrapper( const std::shared_ptr& processor) - : thread_pool_(CreateDefaultThreadPool()), processor_(processor) {} + : thread_pool_(CreateThreadPool()), processor_(processor) {} private: void InvokeProcessor(grpc_auth_context* context, const grpc_metadata* md, diff --git a/src/cpp/server/thread_pool_interface.h b/src/cpp/server/thread_pool_interface.h index 4f4fc7eaaa2..5a182982968 100644 --- a/src/cpp/server/thread_pool_interface.h +++ b/src/cpp/server/thread_pool_interface.h @@ -32,7 +32,11 @@ class ThreadPoolInterface { virtual void Add(const std::function& callback) = 0; }; -ThreadPoolInterface* CreateDefaultThreadPool(); +// Allows different codebases to use their own thread pool impls +typedef ThreadPoolInterface* (*CreateThreadPoolFunc)(void); +void SetCreateThreadPool(CreateThreadPoolFunc func); + +ThreadPoolInterface* CreateThreadPool(); } // namespace grpc From a5d557b96d873873e5f17d96ffca6088e3743af0 Mon Sep 17 00:00:00 2001 From: ncteisen Date: Wed, 5 Jul 2017 15:52:28 -0700 Subject: [PATCH 048/127] Rename function to avoud future clash --- src/cpp/client/secure_credentials.cc | 2 +- src/cpp/server/create_default_thread_pool.cc | 12 ++++-------- src/cpp/server/secure_server_credentials.h | 2 +- src/cpp/server/thread_pool_interface.h | 2 +- 4 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/cpp/client/secure_credentials.cc b/src/cpp/client/secure_credentials.cc index 0eefd0645b4..057a058a3fb 100644 --- a/src/cpp/client/secure_credentials.cc +++ b/src/cpp/client/secure_credentials.cc @@ -207,7 +207,7 @@ void MetadataCredentialsPluginWrapper::InvokePlugin( MetadataCredentialsPluginWrapper::MetadataCredentialsPluginWrapper( std::unique_ptr plugin) - : thread_pool_(CreateThreadPool()), plugin_(std::move(plugin)) {} + : thread_pool_(CreateDefaultThreadPool()), plugin_(std::move(plugin)) {} std::shared_ptr MetadataCredentialsFromPlugin( std::unique_ptr plugin) { diff --git a/src/cpp/server/create_default_thread_pool.cc b/src/cpp/server/create_default_thread_pool.cc index bf76303b454..57faa17f6b9 100644 --- a/src/cpp/server/create_default_thread_pool.cc +++ b/src/cpp/server/create_default_thread_pool.cc @@ -24,21 +24,17 @@ namespace grpc { -static ThreadPoolInterface* CreateDefaultThreadPool() { +static ThreadPoolInterface* CreateDefaultThreadPoolImpl() { int cores = gpr_cpu_num_cores(); if (!cores) cores = 4; return new DynamicThreadPool(cores); } -static CreateThreadPoolFunc g_ctp_impl = CreateDefaultThreadPool; +static CreateThreadPoolFunc g_ctp_impl = CreateDefaultThreadPoolImpl; -ThreadPoolInterface* CreateThreadPool() { - return g_ctp_impl(); -} +ThreadPoolInterface* CreateDefaultThreadPool() { return g_ctp_impl(); } -void SetCreateThreadPool(CreateThreadPoolFunc func) { - g_ctp_impl = func; -} +void SetCreateThreadPool(CreateThreadPoolFunc func) { g_ctp_impl = func; } } // namespace grpc diff --git a/src/cpp/server/secure_server_credentials.h b/src/cpp/server/secure_server_credentials.h index 30ee1c7a366..212f0d1df3b 100644 --- a/src/cpp/server/secure_server_credentials.h +++ b/src/cpp/server/secure_server_credentials.h @@ -39,7 +39,7 @@ class AuthMetadataProcessorAyncWrapper final { AuthMetadataProcessorAyncWrapper( const std::shared_ptr& processor) - : thread_pool_(CreateThreadPool()), processor_(processor) {} + : thread_pool_(CreateDefaultThreadPool()), processor_(processor) {} private: void InvokeProcessor(grpc_auth_context* context, const grpc_metadata* md, diff --git a/src/cpp/server/thread_pool_interface.h b/src/cpp/server/thread_pool_interface.h index 5a182982968..028842a776f 100644 --- a/src/cpp/server/thread_pool_interface.h +++ b/src/cpp/server/thread_pool_interface.h @@ -36,7 +36,7 @@ class ThreadPoolInterface { typedef ThreadPoolInterface* (*CreateThreadPoolFunc)(void); void SetCreateThreadPool(CreateThreadPoolFunc func); -ThreadPoolInterface* CreateThreadPool(); +ThreadPoolInterface* CreateDefaultThreadPool(); } // namespace grpc From eb70b9e0df3b51db4e2d3466607e7713425dfac7 Mon Sep 17 00:00:00 2001 From: ncteisen Date: Thu, 6 Jul 2017 09:38:26 -0700 Subject: [PATCH 049/127] Anon namespace over static --- src/cpp/server/create_default_thread_pool.cc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/cpp/server/create_default_thread_pool.cc b/src/cpp/server/create_default_thread_pool.cc index 57faa17f6b9..8ca3e32c2fb 100644 --- a/src/cpp/server/create_default_thread_pool.cc +++ b/src/cpp/server/create_default_thread_pool.cc @@ -23,14 +23,17 @@ #ifndef GRPC_CUSTOM_DEFAULT_THREAD_POOL namespace grpc { +namespace { -static ThreadPoolInterface* CreateDefaultThreadPoolImpl() { +ThreadPoolInterface* CreateDefaultThreadPoolImpl() { int cores = gpr_cpu_num_cores(); if (!cores) cores = 4; return new DynamicThreadPool(cores); } -static CreateThreadPoolFunc g_ctp_impl = CreateDefaultThreadPoolImpl; +CreateThreadPoolFunc g_ctp_impl = CreateDefaultThreadPoolImpl; + +} // namespace ThreadPoolInterface* CreateDefaultThreadPool() { return g_ctp_impl(); } From 59a19a9d5ecc34b60fd6c035a6cb261261dd48fe Mon Sep 17 00:00:00 2001 From: Alexander Polcyn Date: Tue, 18 Jul 2017 17:26:08 -0700 Subject: [PATCH 050/127] make sure that client-side view of calls is robust --- src/ruby/lib/grpc/generic/active_call.rb | 17 +++- src/ruby/spec/generic/client_stub_spec.rb | 97 ++++++++++++++++++++--- 2 files changed, 104 insertions(+), 10 deletions(-) diff --git a/src/ruby/lib/grpc/generic/active_call.rb b/src/ruby/lib/grpc/generic/active_call.rb index 96c773a995d..4a748a4ac29 100644 --- a/src/ruby/lib/grpc/generic/active_call.rb +++ b/src/ruby/lib/grpc/generic/active_call.rb @@ -46,7 +46,7 @@ module GRPC extend Forwardable attr_reader :deadline, :metadata_sent, :metadata_to_send def_delegators :@call, :cancel, :metadata, :write_flag, :write_flag=, - :peer, :peer_cert, :trailing_metadata + :peer, :peer_cert, :trailing_metadata, :status # client_invoke begins a client invocation. # @@ -105,6 +105,8 @@ module GRPC @input_stream_done = false @call_finished = false @call_finished_mu = Mutex.new + @client_call_executed = false + @client_call_executed_mu = Mutex.new end # Sends the initial metadata that has yet to be sent. @@ -327,6 +329,7 @@ module GRPC # a list, multiple metadata for its key are sent # @return [Object] the response received from the server def request_response(req, metadata: {}) + raise_error_if_already_executed ops = { SEND_MESSAGE => @marshal.call(req), SEND_CLOSE_FROM_CLIENT => nil, @@ -369,6 +372,7 @@ module GRPC # a list, multiple metadata for its key are sent # @return [Object] the response received from the server def client_streamer(requests, metadata: {}) + raise_error_if_already_executed begin merge_metadata_and_send_if_not_already_sent(metadata) requests.each { |r| @call.run_batch(SEND_MESSAGE => @marshal.call(r)) } @@ -411,6 +415,7 @@ module GRPC # a list, multiple metadata for its key are sent # @return [Enumerator|nil] a response Enumerator def server_streamer(req, metadata: {}) + raise_error_if_already_executed ops = { SEND_MESSAGE => @marshal.call(req), SEND_CLOSE_FROM_CLIENT => nil @@ -468,6 +473,7 @@ module GRPC # a list, multiple metadata for its key are sent # @return [Enumerator, nil] a response Enumerator def bidi_streamer(requests, metadata: {}, &blk) + raise_error_if_already_executed # Metadata might have already been sent if this is an operation view merge_metadata_and_send_if_not_already_sent(metadata) bd = BidiCall.new(@call, @@ -572,6 +578,15 @@ module GRPC merge_metadata_to_send(metadata) && send_initial_metadata end + def raise_error_if_already_executed + @client_call_executed_mu.synchronize do + if @client_call_executed + fail GRPC::Core::CallError, 'attempting to re-run a call' + end + @client_call_executed = true + end + end + def self.view_class(*visible_methods) Class.new do extend ::Forwardable diff --git a/src/ruby/spec/generic/client_stub_spec.rb b/src/ruby/spec/generic/client_stub_spec.rb index 3b8f72eda11..7b5e6a95a43 100644 --- a/src/ruby/spec/generic/client_stub_spec.rb +++ b/src/ruby/spec/generic/client_stub_spec.rb @@ -36,6 +36,33 @@ include GRPC::Core::StatusCodes include GRPC::Core::TimeConsts include GRPC::Core::CallOps +# check that methods on a finished/closed call t crash +def check_op_view_of_finished_client_call_is_robust(op_view) + # use read_response_stream to try to iterate through + # possible response stream + fail('need something to attempt reads') unless block_given? + expect do + resp = op_view.execute + yield resp + end.to raise_error(GRPC::Core::CallError) + + expect { op_view.start_call }.to raise_error(RuntimeError) + + expect do + op_view.wait + op_view.cancel + + op_view.metadata + op_view.trailing_metadata + op_view.status + + op_view.cancelled? + op_view.deadline + op_view.write_flag + op_view.write_flag = 1 + end.to_not raise_error +end + describe 'ClientStub' do let(:noop) { proc { |x| x } } @@ -231,15 +258,27 @@ describe 'ClientStub' do it_behaves_like 'request response' - it 'sends metadata to the server ok when running start_call first' do + def run_op_view_metadata_test(run_start_call_first) server_port = create_test_server host = "localhost:#{server_port}" th = run_request_response(@sent_msg, @resp, @pass, k1: 'v1', k2: 'v2') stub = GRPC::ClientStub.new(host, :this_channel_is_insecure) - expect(get_response(stub)).to eq(@resp) + expect( + get_response(stub, + run_start_call_first: run_start_call_first)).to eq(@resp) th.join end + + it 'sends metadata to the server ok when running start_call first' do + run_op_view_metadata_test(true) + check_op_view_of_finished_client_call_is_robust(@op) { |r| p r } + end + + it 'does not crash when used after the call has been finished' do + run_op_view_metadata_test(false) + check_op_view_of_finished_client_call_is_robust(@op) { |r| p r } + end end end @@ -307,11 +346,23 @@ describe 'ClientStub' do it_behaves_like 'client streaming' - it 'sends metadata to the server ok when running start_call first' do + def run_op_view_metadata_test(run_start_call_first) th = run_client_streamer(@sent_msgs, @resp, @pass, **@metadata) - expect(get_response(@stub, run_start_call_first: true)).to eq(@resp) + expect( + get_response(@stub, + run_start_call_first: run_start_call_first)).to eq(@resp) th.join end + + it 'sends metadata to the server ok when running start_call first' do + run_op_view_metadata_test(true) + check_op_view_of_finished_client_call_is_robust(@op) { |r| p r } + end + + it 'does not crash when used after the call has been finished' do + run_op_view_metadata_test(false) + check_op_view_of_finished_client_call_is_robust(@op) { |r| p r } + end end end @@ -377,7 +428,7 @@ describe 'ClientStub' do end end - describe 'without a call operation', test2: true do + describe 'without a call operation' do def get_responses(stub, unmarshal: noop) e = stub.server_streamer(@method, @sent_msg, noop, unmarshal, metadata: @metadata) @@ -405,16 +456,30 @@ describe 'ClientStub' do it_behaves_like 'server streaming' - it 'should send metadata to the server ok when start_call is run first' do + def run_op_view_metadata_test(run_start_call_first) server_port = create_test_server host = "localhost:#{server_port}" th = run_server_streamer(@sent_msg, @replys, @fail, k1: 'v1', k2: 'v2') stub = GRPC::ClientStub.new(host, :this_channel_is_insecure) - e = get_responses(stub, run_start_call_first: true) + e = get_responses(stub, run_start_call_first: run_start_call_first) expect { e.collect { |r| r } }.to raise_error(GRPC::BadStatus) th.join end + + it 'should send metadata to the server ok when start_call is run first' do + run_op_view_metadata_test(true) + check_op_view_of_finished_client_call_is_robust(@op) do |responses| + responses.each { |r| p r } + end + end + + it 'does not crash when used after the call has been finished' do + run_op_view_metadata_test(false) + check_op_view_of_finished_client_call_is_robust(@op) do |responses| + responses.each { |r| p r } + end + end end end @@ -501,14 +566,28 @@ describe 'ClientStub' do it_behaves_like 'bidi streaming' - it 'can run start_call before executing the call' do + def run_op_view_metadata_test(run_start_call_first) th = run_bidi_streamer_handle_inputs_first(@sent_msgs, @replys, @pass) stub = GRPC::ClientStub.new(@host, :this_channel_is_insecure) - e = get_responses(stub, run_start_call_first: true) + e = get_responses(stub, run_start_call_first: run_start_call_first) expect(e.collect { |r| r }).to eq(@replys) th.join end + + it 'can run start_call before executing the call' do + run_op_view_metadata_test(true) + check_op_view_of_finished_client_call_is_robust(@op) do |responses| + responses.each { |r| p r } + end + end + + it 'doesnt crash when op_view used after call has finished' do + run_op_view_metadata_test(false) + check_op_view_of_finished_client_call_is_robust(@op) do |responses| + responses.each { |r| p r } + end + end end end From e6506bc9b2cf32351587e90dca72aa18640615d6 Mon Sep 17 00:00:00 2001 From: Sree Kuchibhotla Date: Tue, 18 Jul 2017 21:43:45 -0700 Subject: [PATCH 051/127] Fix race-condition in epoll1 poller's begin_worker() and pollset_kick() which caused the designated poller to miss a kick in some cases --- src/core/lib/iomgr/ev_epoll1_linux.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/core/lib/iomgr/ev_epoll1_linux.c b/src/core/lib/iomgr/ev_epoll1_linux.c index f579b16fa58..bd7c955d035 100644 --- a/src/core/lib/iomgr/ev_epoll1_linux.c +++ b/src/core/lib/iomgr/ev_epoll1_linux.c @@ -600,6 +600,7 @@ static bool begin_worker(grpc_pollset *pollset, grpc_pollset_worker *worker, } gpr_mu_unlock(&neighbourhood->mu); } + worker_insert(pollset, worker); pollset->begin_refs--; if (worker->kick_state == UNKICKED) { @@ -628,7 +629,18 @@ static bool begin_worker(grpc_pollset *pollset, grpc_pollset_worker *worker, pollset->shutting_down); } - return worker->kick_state == DESIGNATED_POLLER && !pollset->shutting_down; + /* We release pollset lock in this function at a couple of places: + * 1. Brielfly when assigning pollset to a neighbourhood + * 2. When doing gpr_cv_wait() + * It is possible that 'kicked_without_poller' was set to true during (1) and + * 'shutting_down' is set to true during (1) or (2). If either of them is + * true, this worker cannot do polling */ + + /* TODO(sreek): Perhaps there is a better way to handle kicked_without_poller + * case; especially when the worker is the DESIGNATED_POLLER */ + + return worker->kick_state == DESIGNATED_POLLER && !pollset->shutting_down && + !pollset->kicked_without_poller; } static bool check_neighbourhood_for_available_poller( From a0616efadf830db1b861bd96afbac8a47dad26c5 Mon Sep 17 00:00:00 2001 From: Sree Kuchibhotla Date: Tue, 18 Jul 2017 23:49:49 -0700 Subject: [PATCH 052/127] Consume kicked_without_poller --- src/core/lib/iomgr/ev_epoll1_linux.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/core/lib/iomgr/ev_epoll1_linux.c b/src/core/lib/iomgr/ev_epoll1_linux.c index bd7c955d035..77d59059d43 100644 --- a/src/core/lib/iomgr/ev_epoll1_linux.c +++ b/src/core/lib/iomgr/ev_epoll1_linux.c @@ -630,17 +630,20 @@ static bool begin_worker(grpc_pollset *pollset, grpc_pollset_worker *worker, } /* We release pollset lock in this function at a couple of places: - * 1. Brielfly when assigning pollset to a neighbourhood + * 1. Briefly when assigning pollset to a neighbourhood * 2. When doing gpr_cv_wait() * It is possible that 'kicked_without_poller' was set to true during (1) and * 'shutting_down' is set to true during (1) or (2). If either of them is * true, this worker cannot do polling */ - /* TODO(sreek): Perhaps there is a better way to handle kicked_without_poller * case; especially when the worker is the DESIGNATED_POLLER */ - return worker->kick_state == DESIGNATED_POLLER && !pollset->shutting_down && - !pollset->kicked_without_poller; + if (pollset->kicked_without_poller) { + pollset->kicked_without_poller = false; + return false; + } + + return worker->kick_state == DESIGNATED_POLLER && !pollset->shutting_down; } static bool check_neighbourhood_for_available_poller( From 139072ff929891ada8f98f1890d63b45ce049c64 Mon Sep 17 00:00:00 2001 From: ncteisen Date: Thu, 13 Jul 2017 23:47:59 -0700 Subject: [PATCH 053/127] Const correct and clang --- src/core/lib/support/env.h | 2 +- src/core/lib/support/env_linux.c | 15 +++++++-------- src/core/lib/support/env_posix.c | 2 +- src/core/lib/support/env_windows.c | 2 +- src/core/lib/support/log.c | 5 ++--- src/cpp/server/server_builder.cc | 1 - 6 files changed, 12 insertions(+), 15 deletions(-) diff --git a/src/core/lib/support/env.h b/src/core/lib/support/env.h index e1c3bdc66a3..e2c012a7288 100644 --- a/src/core/lib/support/env.h +++ b/src/core/lib/support/env.h @@ -40,7 +40,7 @@ void gpr_setenv(const char *name, const char *value); use an insecure version of the function. It is ONLY to be used to solve the problem in which we need to check an env variable to configure the verbosity level of logging. So DO NOT USE THIS. */ -char *gpr_getenv_silent(const char *name, char** dst); +const char *gpr_getenv_silent(const char *name, char **dst); #ifdef __cplusplus } diff --git a/src/core/lib/support/env_linux.c b/src/core/lib/support/env_linux.c index bc488e1b063..4c45a977caa 100644 --- a/src/core/lib/support/env_linux.c +++ b/src/core/lib/support/env_linux.c @@ -38,10 +38,10 @@ #include "src/core/lib/support/string.h" -char *gpr_getenv_silent(const char *name, char** dst) { - char* insecure_func_used = NULL; - char* result = NULL; - #if defined(GPR_BACKWARDS_COMPATIBILITY_MODE) +const char *gpr_getenv_silent(const char *name, char **dst) { + const char *insecure_func_used = NULL; + char *result = NULL; +#if defined(GPR_BACKWARDS_COMPATIBILITY_MODE) typedef char *(*getenv_type)(const char *); static getenv_type getenv_func = NULL; /* Check to see which getenv variant is supported (go from most @@ -65,11 +65,10 @@ char *gpr_getenv_silent(const char *name, char** dst) { } char *gpr_getenv(const char *name) { - char* result = NULL; - char* insecure_func_used = gpr_getenv_silent(name, &result); + char *result = NULL; + const char *insecure_func_used = gpr_getenv_silent(name, &result); if (insecure_func_used != NULL) { - gpr_log(GPR_DEBUG, - "Warning: insecure environment read function '%s' used", + gpr_log(GPR_DEBUG, "Warning: insecure environment read function '%s' used", insecure_func_used); } return result; diff --git a/src/core/lib/support/env_posix.c b/src/core/lib/support/env_posix.c index 8cc802ef883..b88822ca025 100644 --- a/src/core/lib/support/env_posix.c +++ b/src/core/lib/support/env_posix.c @@ -29,7 +29,7 @@ #include #include "src/core/lib/support/string.h" -char *gpr_getenv_silent(const char *name, char **dst) { +const char *gpr_getenv_silent(const char *name, char **dst) { *dst = gpr_getenv(name); return NULL; } diff --git a/src/core/lib/support/env_windows.c b/src/core/lib/support/env_windows.c index 557d5d6ad50..652eeb61c67 100644 --- a/src/core/lib/support/env_windows.c +++ b/src/core/lib/support/env_windows.c @@ -30,7 +30,7 @@ #include #include -char *gpr_getenv_silent(const char *name, char **dst) { +const char *gpr_getenv_silent(const char *name, char **dst) { *dst = gpr_getenv(name); return NULL; } diff --git a/src/core/lib/support/log.c b/src/core/lib/support/log.c index 010dc65d6ae..fadb4d9a2cf 100644 --- a/src/core/lib/support/log.c +++ b/src/core/lib/support/log.c @@ -65,7 +65,7 @@ void gpr_set_log_verbosity(gpr_log_severity min_severity_to_print) { void gpr_log_verbosity_init() { char *verbosity = NULL; - char *insecure_getenv = gpr_getenv_silent("GRPC_VERBOSITY", &verbosity); + const char *insecure_getenv = gpr_getenv_silent("GRPC_VERBOSITY", &verbosity); gpr_atm min_severity_to_print = GPR_LOG_SEVERITY_ERROR; if (verbosity != NULL) { @@ -84,8 +84,7 @@ void gpr_log_verbosity_init() { } if (insecure_getenv != NULL) { - gpr_log(GPR_DEBUG, - "Warning: insecure environment read function '%s' used", + gpr_log(GPR_DEBUG, "Warning: insecure environment read function '%s' used", insecure_getenv); } } diff --git a/src/cpp/server/server_builder.cc b/src/cpp/server/server_builder.cc index fa3b9cf7660..200e477822c 100644 --- a/src/cpp/server/server_builder.cc +++ b/src/cpp/server/server_builder.cc @@ -250,7 +250,6 @@ std::unique_ptr ServerBuilder::BuildAndStart() { has_sync_methods && num_frequently_polled_cqs > 0; if (has_sync_methods) { - grpc_cq_polling_type polling_type = is_hybrid_server ? GRPC_CQ_NON_POLLING : GRPC_CQ_DEFAULT_POLLING; From 02d426ef6bc3c8babb4535c9ef758cee8eadce39 Mon Sep 17 00:00:00 2001 From: Ben Sykes Date: Tue, 11 Jul 2017 13:58:42 -0700 Subject: [PATCH 054/127] Check for no_proxy environment variable and skip proxy if host is listed This will fix #9989, #11603, #11751. no_proxy is typically comma separated list of hosts and or domains. Matching must be from the end of the uri to accomodate whole domain and subdomain whitelisting. This will work for well-formed no_proxy strings, but may fail if there are additional spaces. --- .../ext/filters/client_channel/http_proxy.c | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/src/core/ext/filters/client_channel/http_proxy.c b/src/core/ext/filters/client_channel/http_proxy.c index cfb5ec6f00e..aa3f61c9917 100644 --- a/src/core/ext/filters/client_channel/http_proxy.c +++ b/src/core/ext/filters/client_channel/http_proxy.c @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -30,6 +31,7 @@ #include "src/core/ext/filters/client_channel/uri_parser.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/support/env.h" +#include "src/core/lib/support/string.h" static char* grpc_get_http_proxy_server(grpc_exec_ctx* exec_ctx) { char* uri_str = gpr_getenv("http_proxy"); @@ -80,6 +82,50 @@ static bool proxy_mapper_map_name(grpc_exec_ctx* exec_ctx, grpc_uri_destroy(uri); return false; } + char* no_proxy_str = gpr_getenv("no_proxy"); + if (no_proxy_str != NULL) { + static const char* NO_PROXY_SEPARATOR = ","; + bool use_proxy = true; + char* server_host; + char* server_port; + if (!gpr_split_host_port(uri->path[0] == '/' ? uri->path + 1 : uri->path, + &server_host, &server_port)) { + gpr_log(GPR_INFO, + "unable to split host and port, not checking no_proxy list for " + "host '%s'", + server_uri); + } else { + size_t uri_len = strlen(server_host); + char** no_proxy_hosts; + size_t num_no_proxy_hosts; + gpr_string_split(no_proxy_str, NO_PROXY_SEPARATOR, &no_proxy_hosts, + &num_no_proxy_hosts); + for (size_t i = 0; i < num_no_proxy_hosts; i++) { + char* no_proxy_entry = no_proxy_hosts[i]; + size_t no_proxy_len = strlen(no_proxy_entry); + if (no_proxy_len <= uri_len && + gpr_stricmp(no_proxy_entry, &server_host[uri_len - no_proxy_len]) == + 0) { + gpr_log(GPR_INFO, "not using proxy for host in no_proxy list '%s'", + server_uri); + use_proxy = false; + break; + } + } + for (size_t i = 0; i < num_no_proxy_hosts; i++) { + gpr_free(no_proxy_hosts[i]); + } + gpr_free(no_proxy_hosts); + gpr_free(server_host); + gpr_free(server_port); + if (!use_proxy) { + grpc_uri_destroy(uri); + gpr_free(*name_to_resolve); + *name_to_resolve = NULL; + return false; + } + } + } grpc_arg new_arg = grpc_channel_arg_string_create( GRPC_ARG_HTTP_CONNECT_SERVER, uri->path[0] == '/' ? uri->path + 1 : uri->path); From 713d7c93a825dc21df0624be314cb2782738ff8b Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Wed, 19 Jul 2017 10:19:28 +0200 Subject: [PATCH 055/127] ruby is already installed on kokoro ubuntu VMs --- tools/internal_ci/linux/grpc_build_artifacts.sh | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tools/internal_ci/linux/grpc_build_artifacts.sh b/tools/internal_ci/linux/grpc_build_artifacts.sh index bc29014ab5f..3997a130878 100755 --- a/tools/internal_ci/linux/grpc_build_artifacts.sh +++ b/tools/internal_ci/linux/grpc_build_artifacts.sh @@ -20,9 +20,10 @@ cd $(dirname $0)/../../.. source tools/internal_ci/helper_scripts/prepare_build_linux_rc -# TODO(jtattermusch): install ruby on the internal_ci worker -gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 -# TODO(jtattermusch): grep works around https://github.com/rvm/rvm/issues/4068 -curl -sSL https://get.rvm.io | grep -v __rvm_print_headline | bash -s stable --ruby +set +ex +[[ -s /etc/profile.d/rvm.sh ]] && . /etc/profile.d/rvm.sh +set -e # rvm commands are very verbose +rvm --default use ruby-2.4.1 +set -ex tools/run_tests/task_runner.py -f artifact linux From 6617790c18e4048671d64d03212cfe84b960f376 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 18 Jul 2017 18:00:38 -0700 Subject: [PATCH 056/127] Add SO_REUSEPORT support to uv iomgr code --- src/core/lib/iomgr/sockaddr_utils.c | 5 +++++ src/core/lib/iomgr/sockaddr_utils.h | 2 ++ src/core/lib/iomgr/tcp_server_uv.c | 14 +++++++++++++- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/core/lib/iomgr/sockaddr_utils.c b/src/core/lib/iomgr/sockaddr_utils.c index 99dc2f1c78a..3f4145d104e 100644 --- a/src/core/lib/iomgr/sockaddr_utils.c +++ b/src/core/lib/iomgr/sockaddr_utils.c @@ -220,6 +220,11 @@ const char *grpc_sockaddr_get_uri_scheme( return NULL; } +int grpc_sockaddr_get_family(const grpc_resolved_address *resolved_addr) { + const struct sockaddr *addr = (const struct sockaddr *)resolved_addr->addr; + return addr->sa_family; +} + int grpc_sockaddr_get_port(const grpc_resolved_address *resolved_addr) { const struct sockaddr *addr = (const struct sockaddr *)resolved_addr->addr; switch (addr->sa_family) { diff --git a/src/core/lib/iomgr/sockaddr_utils.h b/src/core/lib/iomgr/sockaddr_utils.h index 7692b969f2b..a589a197054 100644 --- a/src/core/lib/iomgr/sockaddr_utils.h +++ b/src/core/lib/iomgr/sockaddr_utils.h @@ -75,4 +75,6 @@ char *grpc_sockaddr_to_uri(const grpc_resolved_address *addr); /* Returns the URI scheme corresponding to \a addr */ const char *grpc_sockaddr_get_uri_scheme(const grpc_resolved_address *addr); +int grpc_sockaddr_get_family(const grpc_resolved_address *resolved_addr); + #endif /* GRPC_CORE_LIB_IOMGR_SOCKADDR_UTILS_H */ diff --git a/src/core/lib/iomgr/tcp_server_uv.c b/src/core/lib/iomgr/tcp_server_uv.c index 2ab836cc34d..079c9135796 100644 --- a/src/core/lib/iomgr/tcp_server_uv.c +++ b/src/core/lib/iomgr/tcp_server_uv.c @@ -316,6 +316,7 @@ grpc_error *grpc_tcp_server_add_port(grpc_tcp_server *s, unsigned port_index = 0; int status; grpc_error *error = GRPC_ERROR_NONE; + int family; if (s->tail != NULL) { port_index = s->tail->port_index + 1; @@ -353,7 +354,18 @@ grpc_error *grpc_tcp_server_add_port(grpc_tcp_server *s, } handle = gpr_malloc(sizeof(uv_tcp_t)); - status = uv_tcp_init(uv_default_loop(), handle); + + family = grpc_sockaddr_get_family(addr); + status = uv_tcp_init_ex(uv_default_loop(), handle, (unsigned int)family); +#if defined(GPR_LINUX) && defined(SO_REUSEPORT) + if (family == AF_INET || family == AF_INET6) { + int fd; + uv_fileno((uv_handle_t *)handle, &fd); + int enable = 1; + setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(enable)); + } +#endif /* GPR_LINUX && SO_REUSEPORT */ + if (status == 0) { error = add_socket_to_server(s, handle, addr, port_index, &sp); } else { From f7350ea6b7b58d632bf4a8aafaa0354e022d9c0b Mon Sep 17 00:00:00 2001 From: Yash Tibrewal Date: Wed, 19 Jul 2017 10:26:41 -0700 Subject: [PATCH 057/127] Adding connect auth feature. Proxy-Authorization header is being inserted when user creds are present in uri --- CMakeLists.txt | 2 + Makefile | 2 + .../ext/filters/client_channel/http_proxy.c | 53 +- test/core/end2end/end2end_nosec_tests.c | 8 + test/core/end2end/end2end_tests.c | 8 + test/core/end2end/fixtures/h2_http_proxy.c | 30 +- .../end2end/fixtures/http_proxy_fixture.c | 43 +- .../end2end/fixtures/http_proxy_fixture.h | 21 +- test/core/end2end/gen_build_yaml.py | 1 + test/core/end2end/generate_tests.bzl | 1 + .../end2end/tests/payload_with_proxy_auth.c | 302 ++++++ .../generated/sources_and_headers.json | 2 + tools/run_tests/generated/tests.json | 904 ++++++++++++++++-- .../end2end_nosec_tests.vcxproj | 2 + .../end2end_nosec_tests.vcxproj.filters | 3 + .../tests/end2end_tests/end2end_tests.vcxproj | 2 + .../end2end_tests.vcxproj.filters | 3 + 17 files changed, 1300 insertions(+), 87 deletions(-) create mode 100644 test/core/end2end/tests/payload_with_proxy_auth.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 3dd8ec45037..3b20c045943 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4337,6 +4337,7 @@ add_library(end2end_tests test/core/end2end/tests/no_logging.c test/core/end2end/tests/no_op.c test/core/end2end/tests/payload.c + test/core/end2end/tests/payload_with_proxy_auth.c test/core/end2end/tests/ping.c test/core/end2end/tests/ping_pong_streaming.c test/core/end2end/tests/registered_call.c @@ -4436,6 +4437,7 @@ add_library(end2end_nosec_tests test/core/end2end/tests/no_logging.c test/core/end2end/tests/no_op.c test/core/end2end/tests/payload.c + test/core/end2end/tests/payload_with_proxy_auth.c test/core/end2end/tests/ping.c test/core/end2end/tests/ping_pong_streaming.c test/core/end2end/tests/registered_call.c diff --git a/Makefile b/Makefile index f58a02df9ae..e68ccae3b07 100644 --- a/Makefile +++ b/Makefile @@ -7926,6 +7926,7 @@ LIBEND2END_TESTS_SRC = \ test/core/end2end/tests/no_logging.c \ test/core/end2end/tests/no_op.c \ test/core/end2end/tests/payload.c \ + test/core/end2end/tests/payload_with_proxy_auth.c \ test/core/end2end/tests/ping.c \ test/core/end2end/tests/ping_pong_streaming.c \ test/core/end2end/tests/registered_call.c \ @@ -8020,6 +8021,7 @@ LIBEND2END_NOSEC_TESTS_SRC = \ test/core/end2end/tests/no_logging.c \ test/core/end2end/tests/no_op.c \ test/core/end2end/tests/payload.c \ + test/core/end2end/tests/payload_with_proxy_auth.c \ test/core/end2end/tests/ping.c \ test/core/end2end/tests/ping_pong_streaming.c \ test/core/end2end/tests/registered_call.c \ diff --git a/src/core/ext/filters/client_channel/http_proxy.c b/src/core/ext/filters/client_channel/http_proxy.c index cfb5ec6f00e..faa4b3c319c 100644 --- a/src/core/ext/filters/client_channel/http_proxy.c +++ b/src/core/ext/filters/client_channel/http_proxy.c @@ -30,13 +30,17 @@ #include "src/core/ext/filters/client_channel/uri_parser.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/support/env.h" +#include "src/core/lib/support/string.h" +#include "src/core/lib/slice/b64.h" -static char* grpc_get_http_proxy_server(grpc_exec_ctx* exec_ctx) { +static void grpc_get_http_proxy_server(grpc_exec_ctx* exec_ctx, + char **name_to_resolve, + char **user_cred) { + *name_to_resolve = NULL; char* uri_str = gpr_getenv("http_proxy"); - if (uri_str == NULL) return NULL; + if (uri_str == NULL) return; grpc_uri* uri = grpc_uri_parse(exec_ctx, uri_str, false /* suppress_errors */); - char* proxy_name = NULL; if (uri == NULL || uri->authority == NULL) { gpr_log(GPR_ERROR, "cannot parse value of 'http_proxy' env var"); goto done; @@ -45,15 +49,18 @@ static char* grpc_get_http_proxy_server(grpc_exec_ctx* exec_ctx) { gpr_log(GPR_ERROR, "'%s' scheme not supported in proxy URI", uri->scheme); goto done; } - if (strchr(uri->authority, '@') != NULL) { - gpr_log(GPR_ERROR, "userinfo not supported in proxy URI"); - goto done; + char *user_cred_end = strchr(uri->authority, '@'); + if (user_cred_end != NULL) { + *name_to_resolve = gpr_strdup(user_cred_end + 1); + *user_cred_end = '\0'; + *user_cred = gpr_strdup(uri->authority); + gpr_log(GPR_INFO, "userinfo found in proxy URI"); + } else { + *name_to_resolve = gpr_strdup(uri->authority); } - proxy_name = gpr_strdup(uri->authority); done: gpr_free(uri_str); grpc_uri_destroy(uri); - return proxy_name; } static bool proxy_mapper_map_name(grpc_exec_ctx* exec_ctx, @@ -62,7 +69,8 @@ static bool proxy_mapper_map_name(grpc_exec_ctx* exec_ctx, const grpc_channel_args* args, char** name_to_resolve, grpc_channel_args** new_args) { - *name_to_resolve = grpc_get_http_proxy_server(exec_ctx); + char *user_cred = NULL; + grpc_get_http_proxy_server(exec_ctx, name_to_resolve, &user_cred); if (*name_to_resolve == NULL) return false; grpc_uri* uri = grpc_uri_parse(exec_ctx, server_uri, false /* suppress_errors */); @@ -71,19 +79,40 @@ static bool proxy_mapper_map_name(grpc_exec_ctx* exec_ctx, "'http_proxy' environment variable set, but cannot " "parse server URI '%s' -- not using proxy", server_uri); - if (uri != NULL) grpc_uri_destroy(uri); + if (uri != NULL) { + gpr_free(user_cred); + grpc_uri_destroy(uri); + } return false; } if (strcmp(uri->scheme, "unix") == 0) { gpr_log(GPR_INFO, "not using proxy for Unix domain socket '%s'", server_uri); + gpr_free(user_cred); grpc_uri_destroy(uri); return false; } - grpc_arg new_arg = grpc_channel_arg_string_create( + + grpc_arg args_to_add[2]; + args_to_add[0] = grpc_channel_arg_string_create( GRPC_ARG_HTTP_CONNECT_SERVER, uri->path[0] == '/' ? uri->path + 1 : uri->path); - *new_args = grpc_channel_args_copy_and_add(args, &new_arg, 1); + + if(user_cred != NULL) { + /* Use base64 encoding for user credentials */ + char *encoded_user_cred = + grpc_base64_encode(user_auth, strlen(user_cred), 0, 0); + char *header; + gpr_asprintf(&header, "Proxy-Authorization:Basic %s", encoded_user_cred); + gpr_free(encoded_user_cred); + args_to_add[1] = grpc_channel_arg_string_create( + GRPC_ARG_HTTP_CONNECT_HEADERS, header); + *new_args = grpc_channel_args_copy_and_add(args, args_to_add, 2); + gpr_free(header); + } else { + *new_args = grpc_channel_args_copy_and_add(args, args_to_add, 1); + } + gpr_free(user_cred); grpc_uri_destroy(uri); return true; } diff --git a/test/core/end2end/end2end_nosec_tests.c b/test/core/end2end/end2end_nosec_tests.c index ae1db54f1a8..483f84e7837 100644 --- a/test/core/end2end/end2end_nosec_tests.c +++ b/test/core/end2end/end2end_nosec_tests.c @@ -102,6 +102,8 @@ extern void no_op(grpc_end2end_test_config config); extern void no_op_pre_init(void); extern void payload(grpc_end2end_test_config config); extern void payload_pre_init(void); +extern void payload_with_proxy_auth(grpc_end2end_test_config config); +extern void payload_with_proxy_auth_pre_init(void); extern void ping(grpc_end2end_test_config config); extern void ping_pre_init(void); extern void ping_pong_streaming(grpc_end2end_test_config config); @@ -179,6 +181,7 @@ void grpc_end2end_tests_pre_init(void) { no_logging_pre_init(); no_op_pre_init(); payload_pre_init(); + payload_with_proxy_auth_pre_init(); ping_pre_init(); ping_pong_streaming_pre_init(); registered_call_pre_init(); @@ -242,6 +245,7 @@ void grpc_end2end_tests(int argc, char **argv, no_logging(config); no_op(config); payload(config); + payload_with_proxy_auth(config); ping(config); ping_pong_streaming(config); registered_call(config); @@ -408,6 +412,10 @@ void grpc_end2end_tests(int argc, char **argv, payload(config); continue; } + if (0 == strcmp("payload_with_proxy_auth", argv[i])) { + payload_with_proxy_auth(config); + continue; + } if (0 == strcmp("ping", argv[i])) { ping(config); continue; diff --git a/test/core/end2end/end2end_tests.c b/test/core/end2end/end2end_tests.c index d18dd9c7b6b..745546dbb7f 100644 --- a/test/core/end2end/end2end_tests.c +++ b/test/core/end2end/end2end_tests.c @@ -104,6 +104,8 @@ extern void no_op(grpc_end2end_test_config config); extern void no_op_pre_init(void); extern void payload(grpc_end2end_test_config config); extern void payload_pre_init(void); +extern void payload_with_proxy_auth(grpc_end2end_test_config config); +extern void payload_with_proxy_auth_pre_init(void); extern void ping(grpc_end2end_test_config config); extern void ping_pre_init(void); extern void ping_pong_streaming(grpc_end2end_test_config config); @@ -182,6 +184,7 @@ void grpc_end2end_tests_pre_init(void) { no_logging_pre_init(); no_op_pre_init(); payload_pre_init(); + payload_with_proxy_auth_pre_init(); ping_pre_init(); ping_pong_streaming_pre_init(); registered_call_pre_init(); @@ -246,6 +249,7 @@ void grpc_end2end_tests(int argc, char **argv, no_logging(config); no_op(config); payload(config); + payload_with_proxy_auth(config); ping(config); ping_pong_streaming(config); registered_call(config); @@ -416,6 +420,10 @@ void grpc_end2end_tests(int argc, char **argv, payload(config); continue; } + if (0 == strcmp("payload_with_proxy_auth", argv[i])) { + payload_with_proxy_auth(config); + continue; + } if (0 == strcmp("ping", argv[i])) { ping(config); continue; diff --git a/test/core/end2end/fixtures/h2_http_proxy.c b/test/core/end2end/fixtures/h2_http_proxy.c index f8c88e59537..f87036d52e2 100644 --- a/test/core/end2end/fixtures/h2_http_proxy.c +++ b/test/core/end2end/fixtures/h2_http_proxy.c @@ -47,11 +47,26 @@ static grpc_end2end_test_fixture chttp2_create_fixture_fullstack( grpc_channel_args *client_args, grpc_channel_args *server_args) { grpc_end2end_test_fixture f; memset(&f, 0, sizeof(f)); + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; fullstack_fixture_data *ffd = gpr_malloc(sizeof(fullstack_fixture_data)); const int server_port = grpc_pick_unused_port_or_die(); gpr_join_host_port(&ffd->server_addr, "localhost", server_port); - ffd->proxy = grpc_end2end_http_proxy_create(); + + /*const grpc_arg *proxy_auth_arg = + grpc_channel_args_find(client_args, "test_uses_proxy_auth"); + ffd->proxy = grpc_end2end_http_proxy_create(proxy_args);*/ + //If we are testing proxy auth, add the proxy auth arg to proxy channel args + grpc_channel_args *proxy_args = NULL; + const grpc_arg *proxy_auth_arg = grpc_channel_args_find( + client_args, GRPC_END2END_HTTP_PROXY_TEST_CONNECT_AUTH_PRESENT); + if(proxy_auth_arg) { + proxy_args = grpc_channel_args_copy_and_add(NULL, proxy_auth_arg, 1); + } + ffd->proxy = grpc_end2end_http_proxy_create(proxy_args); + grpc_channel_args_destroy(&exec_ctx, proxy_args); + + grpc_exec_ctx_finish(&exec_ctx); f.fixture_data = ffd; f.cq = grpc_completion_queue_create_for_next(NULL); @@ -64,8 +79,17 @@ void chttp2_init_client_fullstack(grpc_end2end_test_fixture *f, grpc_channel_args *client_args) { fullstack_fixture_data *ffd = f->fixture_data; char *proxy_uri; - gpr_asprintf(&proxy_uri, "http://%s", - grpc_end2end_http_proxy_get_proxy_name(ffd->proxy)); + + // If testing for proxy auth, add credentials to proxy uri + if(grpc_channel_args_find( + client_args, GRPC_END2END_HTTP_PROXY_TEST_CONNECT_AUTH_PRESENT) == NULL) { + gpr_asprintf(&proxy_uri, "http://%s", + grpc_end2end_http_proxy_get_proxy_name(ffd->proxy)); + } else { + gpr_asprintf(&proxy_uri, "http://%s@%s", + GRPC_END2END_HTTP_PROXY_TEST_CONNECT_CRED, + grpc_end2end_http_proxy_get_proxy_name(ffd->proxy)); + } gpr_setenv("http_proxy", proxy_uri); gpr_free(proxy_uri); f->client = grpc_insecure_channel_create(ffd->server_addr, client_args, NULL); diff --git a/test/core/end2end/fixtures/http_proxy_fixture.c b/test/core/end2end/fixtures/http_proxy_fixture.c index 54693c49001..d69ed1a0866 100644 --- a/test/core/end2end/fixtures/http_proxy_fixture.c +++ b/test/core/end2end/fixtures/http_proxy_fixture.c @@ -22,6 +22,7 @@ #include +#include #include #include #include @@ -47,6 +48,7 @@ #include "src/core/lib/iomgr/tcp_server.h" #include "src/core/lib/iomgr/timer.h" #include "src/core/lib/slice/slice_internal.h" +#include "src/core/lib/slice/b64.h" #include "test/core/util/port.h" struct grpc_end2end_http_proxy { @@ -352,6 +354,42 @@ static void on_read_request_done(grpc_exec_ctx* exec_ctx, void* arg, GRPC_ERROR_UNREF(error); return; } + // If proxy auth is being used, check if the header is present + if(grpc_channel_args_find( + conn->proxy->channel_args, + GRPC_END2END_HTTP_PROXY_TEST_CONNECT_AUTH_PRESENT) != NULL) { + bool found = false, failed = false; + for(size_t i = 0; i < conn->http_request.hdr_count; i++) { + if(strcmp(conn->http_request.hdrs[i].key, "Proxy-Authorization") == 0) { + found = true; + // Authentication type should be Basic + if(strncmp(conn->http_request.hdrs[i].value, "Basic", + strlen("Basic")) != 0) { + failed = true; + break; + } + // Check if encoded string is as expected + char *encoded_str_start = + strchr(conn->http_request.hdrs[i].value, ' ') + 1; + grpc_slice decoded_slice = + grpc_base64_decode(exec_ctx, encoded_str_start, 0); + if(grpc_slice_str_cmp( + decoded_slice, GRPC_END2END_HTTP_PROXY_TEST_CONNECT_CRED) != 0) { + failed = true; + break; + } + break; + } + } + if(!found || failed) { + const char *msg = "HTTP Connect could not verify authentication"; + error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); + proxy_connection_failed(exec_ctx, conn, true /* is_client */, + "HTTP proxy read request", error); + GRPC_ERROR_UNREF(error); + return; + } + } // Resolve address. grpc_resolved_addresses* resolved_addresses = NULL; error = grpc_blocking_resolve_address(conn->http_request.path, "80", @@ -436,7 +474,8 @@ static void thread_main(void* arg) { grpc_exec_ctx_finish(&exec_ctx); } -grpc_end2end_http_proxy* grpc_end2end_http_proxy_create(void) { +grpc_end2end_http_proxy* grpc_end2end_http_proxy_create( + grpc_channel_args *args) { grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_end2end_http_proxy* proxy = (grpc_end2end_http_proxy*)gpr_malloc(sizeof(*proxy)); @@ -448,7 +487,7 @@ grpc_end2end_http_proxy* grpc_end2end_http_proxy_create(void) { gpr_join_host_port(&proxy->proxy_name, "localhost", proxy_port); gpr_log(GPR_INFO, "Proxy address: %s", proxy->proxy_name); // Create TCP server. - proxy->channel_args = grpc_channel_args_copy(NULL); + proxy->channel_args = grpc_channel_args_copy(args); grpc_error* error = grpc_tcp_server_create( &exec_ctx, NULL, proxy->channel_args, &proxy->server); GPR_ASSERT(error == GRPC_ERROR_NONE); diff --git a/test/core/end2end/fixtures/http_proxy_fixture.h b/test/core/end2end/fixtures/http_proxy_fixture.h index a72162e846c..f3da0494ae0 100644 --- a/test/core/end2end/fixtures/http_proxy_fixture.h +++ b/test/core/end2end/fixtures/http_proxy_fixture.h @@ -16,11 +16,30 @@ * */ +#ifndef GRPC_TEST_CORE_END2END_FIXTURES_HTTP_PROXY_FIXTURE_H +#define GRPC_TEST_CORE_END2END_FIXTURES_HTTP_PROXY_FIXTURE_H + +#include + +/* The test credentials being used for HTTP Proxy Authorization */ +#define GRPC_END2END_HTTP_PROXY_TEST_CONNECT_CRED "aladdin:opensesame" + +/* A channel arg key used to indicate that the channel uses proxy authorization. + * The value is of no consequence as just the presence of the argument is + * enough. It is currently kept as of type integer but can be changed as seen + * fit. + */ +#define GRPC_END2END_HTTP_PROXY_TEST_CONNECT_AUTH_PRESENT \ + "grpc.test.connect_auth" + typedef struct grpc_end2end_http_proxy grpc_end2end_http_proxy; -grpc_end2end_http_proxy* grpc_end2end_http_proxy_create(); +grpc_end2end_http_proxy* grpc_end2end_http_proxy_create( + grpc_channel_args *args); void grpc_end2end_http_proxy_destroy(grpc_end2end_http_proxy* proxy); const char* grpc_end2end_http_proxy_get_proxy_name( grpc_end2end_http_proxy* proxy); + +#endif /* GRPC_TEST_CORE_END2END_FIXTURES_HTTP_PROXY_FIXTURE_H */ diff --git a/test/core/end2end/gen_build_yaml.py b/test/core/end2end/gen_build_yaml.py index 6dffacf9d71..53ee9622226 100755 --- a/test/core/end2end/gen_build_yaml.py +++ b/test/core/end2end/gen_build_yaml.py @@ -122,6 +122,7 @@ END2END_TESTS = { 'no_logging': default_test_options._replace(traceable=False), 'no_op': default_test_options, 'payload': default_test_options, + 'payload_with_proxy_auth': default_test_options, 'load_reporting_hook': default_test_options, 'ping_pong_streaming': default_test_options._replace(cpu_cost=LOWCPU), 'ping': connectivity_test_options._replace(proxyable=False, cpu_cost=LOWCPU), diff --git a/test/core/end2end/generate_tests.bzl b/test/core/end2end/generate_tests.bzl index 3312f4e596c..57dffd4a3d0 100755 --- a/test/core/end2end/generate_tests.bzl +++ b/test/core/end2end/generate_tests.bzl @@ -106,6 +106,7 @@ END2END_TESTS = { 'no_logging': test_options(traceable=False), 'no_op': test_options(), 'payload': test_options(), + 'payload_with_proxy_auth': test_options(), 'load_reporting_hook': test_options(), 'ping_pong_streaming': test_options(), 'ping': test_options(needs_fullstack=True, proxyable=False), diff --git a/test/core/end2end/tests/payload_with_proxy_auth.c b/test/core/end2end/tests/payload_with_proxy_auth.c new file mode 100644 index 00000000000..4d176f9145b --- /dev/null +++ b/test/core/end2end/tests/payload_with_proxy_auth.c @@ -0,0 +1,302 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "test/core/end2end/end2end_tests.h" +#include "test/core/end2end/fixtures/http_proxy_fixture.h" + +#include +#include + +#include +#include +#include +#include +#include +#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, "Running test: %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); + return f; +} + +static gpr_timespec n_seconds_from_now(int n) { + return grpc_timeout_seconds_to_deadline(n); +} + +static gpr_timespec five_seconds_from_now(void) { + return n_seconds_from_now(5); +} + +static void drain_cq(grpc_completion_queue *cq) { + grpc_event ev; + do { + ev = grpc_completion_queue_next(cq, five_seconds_from_now(), 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->shutdown_cq, tag(1000)); + GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_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); + grpc_completion_queue_destroy(f->shutdown_cq); +} + +/* Creates and returns a grpc_slice containing random alphanumeric characters. + */ +static grpc_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'; + grpc_slice out = grpc_slice_from_copied_string(output); + gpr_free(output); + return out; +} + +static void request_response_with_payload_and_proxy_auth + (grpc_end2end_test_config config, + grpc_end2end_test_fixture f) { + /* 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. */ + grpc_slice request_payload_slice = generate_random_slice(); + grpc_slice response_payload_slice = generate_random_slice(); + + grpc_call *c; + grpc_call *s; + grpc_byte_buffer *request_payload = + grpc_raw_byte_buffer_create(&request_payload_slice, 1); + grpc_byte_buffer *response_payload = + grpc_raw_byte_buffer_create(&response_payload_slice, 1); + cq_verifier *cqv = cq_verifier_create(f.cq); + grpc_op ops[6]; + grpc_op *op; + grpc_metadata_array initial_metadata_recv; + grpc_metadata_array trailing_metadata_recv; + grpc_metadata_array request_metadata_recv; + grpc_byte_buffer *request_payload_recv = NULL; + grpc_byte_buffer *response_payload_recv = NULL; + grpc_call_details call_details; + grpc_status_code status; + grpc_call_error error; + grpc_slice details; + int was_cancelled = 2; + + gpr_timespec deadline = n_seconds_from_now(60); + c = grpc_channel_create_call( + f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, + grpc_slice_from_static_string("/foo"), + get_host_override_slice("foo.test.google.fr:1234", config), deadline, + NULL); + GPR_ASSERT(c); + + grpc_metadata_array_init(&initial_metadata_recv); + grpc_metadata_array_init(&trailing_metadata_recv); + grpc_metadata_array_init(&request_metadata_recv); + grpc_call_details_init(&call_details); + + 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.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.recv_initial_metadata = &initial_metadata_recv; + op->flags = 0; + op->reserved = NULL; + op++; + op->op = GRPC_OP_RECV_MESSAGE; + op->data.recv_message.recv_message = &response_payload_recv; + 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; + op->data.recv_status_on_client.status = &status; + op->data.recv_status_on_client.status_details = &details; + op->flags = 0; + op->reserved = NULL; + op++; + error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), NULL); + GPR_ASSERT(GRPC_CALL_OK == error); + + error = + grpc_server_request_call(f.server, &s, &call_details, + &request_metadata_recv, f.cq, f.cq, tag(101)); + GPR_ASSERT(GRPC_CALL_OK == error); + CQ_EXPECT_COMPLETION(cqv, tag(101), 1); + cq_verify(cqv); + + 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.recv_message = &request_payload_recv; + op->flags = 0; + op->reserved = NULL; + op++; + error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), NULL); + GPR_ASSERT(GRPC_CALL_OK == error); + + CQ_EXPECT_COMPLETION(cqv, tag(102), 1); + cq_verify(cqv); + + memset(ops, 0, sizeof(ops)); + op = ops; + op->op = GRPC_OP_RECV_CLOSE_ON_SERVER; + op->data.recv_close_on_server.cancelled = &was_cancelled; + op->flags = 0; + op->reserved = NULL; + op++; + op->op = GRPC_OP_SEND_MESSAGE; + op->data.send_message.send_message = response_payload; + 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; + grpc_slice status_details = grpc_slice_from_static_string("xyz"); + op->data.send_status_from_server.status_details = &status_details; + op->flags = 0; + op->reserved = NULL; + op++; + error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), NULL); + GPR_ASSERT(GRPC_CALL_OK == error); + + CQ_EXPECT_COMPLETION(cqv, tag(103), 1); + CQ_EXPECT_COMPLETION(cqv, tag(1), 1); + cq_verify(cqv); + + GPR_ASSERT(status == GRPC_STATUS_OK); + GPR_ASSERT(0 == grpc_slice_str_cmp(details, "xyz")); + GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/foo")); + validate_host_override_string("foo.test.google.fr:1234", call_details.host, + config); + GPR_ASSERT(was_cancelled == 0); + GPR_ASSERT(byte_buffer_eq_slice(request_payload_recv, request_payload_slice)); + GPR_ASSERT( + byte_buffer_eq_slice(response_payload_recv, response_payload_slice)); + + grpc_slice_unref(details); + grpc_metadata_array_destroy(&initial_metadata_recv); + grpc_metadata_array_destroy(&trailing_metadata_recv); + grpc_metadata_array_destroy(&request_metadata_recv); + grpc_call_details_destroy(&call_details); + + grpc_call_unref(c); + grpc_call_unref(s); + + cq_verifier_destroy(cqv); + + grpc_byte_buffer_destroy(request_payload); + grpc_byte_buffer_destroy(response_payload); + grpc_byte_buffer_destroy(request_payload_recv); + grpc_byte_buffer_destroy(response_payload_recv); +} + +/* Client sends a request with payload, server reads then returns a response + payload and status. */ +static void test_invoke_request_response_with_payload_and_proxy_auth( + grpc_end2end_test_config config) { + /* Indicate that the proxy requires user auth */ + grpc_arg client_arg = {.type = GRPC_ARG_INTEGER, + .key = GRPC_END2END_HTTP_PROXY_TEST_CONNECT_AUTH_PRESENT, + .value.integer = 0}; + grpc_channel_args client_args = {.num_args = 1, .args = &client_arg}; + grpc_end2end_test_fixture f = begin_test( + config, "test_invoke_request_response_with_payload_and_proxy_auth", + &client_args, NULL); + request_response_with_payload_and_proxy_auth(config, f); + end_test(&f); + config.tear_down_data(&f); +} + +static void test_invoke_10_request_response_with_payload_and_proxy_auth( + grpc_end2end_test_config config) { + int i; + /* Indicate that the proxy requires user auth */ + grpc_arg client_arg = {.type = GRPC_ARG_INTEGER, + .key = GRPC_END2END_HTTP_PROXY_TEST_CONNECT_AUTH_PRESENT, + .value.integer = 0}; + grpc_channel_args client_args = {.num_args = 1, .args = &client_arg}; + grpc_end2end_test_fixture f = begin_test( + config, "test_invoke_10_request_response_with_payload_and_proxy_auth", + &client_args, NULL); + for (i = 0; i < 10; i++) { + request_response_with_payload_and_proxy_auth(config, f); + } + end_test(&f); + config.tear_down_data(&f); +} + +void payload_with_proxy_auth(grpc_end2end_test_config config) { + test_invoke_request_response_with_payload_and_proxy_auth(config); + test_invoke_10_request_response_with_payload_and_proxy_auth(config); +} + +void payload_with_proxy_auth_pre_init(void) {} diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json index 02562bfae4d..61eab0bac9d 100644 --- a/tools/run_tests/generated/sources_and_headers.json +++ b/tools/run_tests/generated/sources_and_headers.json @@ -7256,6 +7256,7 @@ "test/core/end2end/tests/no_logging.c", "test/core/end2end/tests/no_op.c", "test/core/end2end/tests/payload.c", + "test/core/end2end/tests/payload_with_proxy_auth.c", "test/core/end2end/tests/ping.c", "test/core/end2end/tests/ping_pong_streaming.c", "test/core/end2end/tests/registered_call.c", @@ -7333,6 +7334,7 @@ "test/core/end2end/tests/no_logging.c", "test/core/end2end/tests/no_op.c", "test/core/end2end/tests/payload.c", + "test/core/end2end/tests/payload_with_proxy_auth.c", "test/core/end2end/tests/ping.c", "test/core/end2end/tests/ping_pong_streaming.c", "test/core/end2end/tests/registered_call.c", diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json index dd812414b9f..f71da435163 100644 --- a/tools/run_tests/generated/tests.json +++ b/tools/run_tests/generated/tests.json @@ -6585,6 +6585,29 @@ "posix" ] }, + { + "args": [ + "payload_with_proxy_auth" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "language": "c", + "name": "h2_census_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, { "args": [ "ping" @@ -7854,6 +7877,29 @@ "posix" ] }, + { + "args": [ + "payload_with_proxy_auth" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "language": "c", + "name": "h2_compress_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, { "args": [ "ping" @@ -9063,6 +9109,28 @@ "posix" ] }, + { + "args": [ + "payload_with_proxy_auth" + ], + "ci_platforms": [ + "windows", + "linux", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "language": "c", + "name": "h2_fakesec_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, { "args": [ "ping" @@ -10195,6 +10263,29 @@ "posix" ] }, + { + "args": [ + "payload_with_proxy_auth" + ], + "ci_platforms": [ + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [ + "uv" + ], + "flaky": false, + "language": "c", + "name": "h2_fd_test", + "platforms": [ + "linux", + "mac", + "posix" + ] + }, { "args": [ "ping_pong_streaming" @@ -11418,6 +11509,29 @@ "posix" ] }, + { + "args": [ + "payload_with_proxy_auth" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "language": "c", + "name": "h2_full_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, { "args": [ "ping" @@ -12535,6 +12649,25 @@ "linux" ] }, + { + "args": [ + "payload_with_proxy_auth" + ], + "ci_platforms": [ + "linux" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [ + "uv" + ], + "flaky": false, + "language": "c", + "name": "h2_full+pipe_test", + "platforms": [ + "linux" + ] + }, { "args": [ "ping" @@ -13686,6 +13819,29 @@ "posix" ] }, + { + "args": [ + "payload_with_proxy_auth" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "language": "c", + "name": "h2_full+trace_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, { "args": [ "ping" @@ -14955,6 +15111,29 @@ "posix" ] }, + { + "args": [ + "payload_with_proxy_auth" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "language": "c", + "name": "h2_full+workarounds_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, { "args": [ "ping" @@ -16257,6 +16436,30 @@ "posix" ] }, + { + "args": [ + "payload_with_proxy_auth" + ], + "ci_platforms": [ + "windows", + "linux", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [ + "uv" + ], + "flaky": false, + "language": "c", + "name": "h2_http_proxy_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, { "args": [ "ping" @@ -17544,6 +17747,29 @@ "posix" ] }, + { + "args": [ + "payload_with_proxy_auth" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "language": "c", + "name": "h2_load_reporting_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, { "args": [ "ping" @@ -18848,14 +19074,14 @@ }, { "args": [ - "ping" + "payload_with_proxy_auth" ], "ci_platforms": [ "windows", "linux", "posix" ], - "cpu_cost": 0.1, + "cpu_cost": 1.0, "exclude_configs": [], "exclude_iomgrs": [ "uv" @@ -18872,7 +19098,7 @@ }, { "args": [ - "ping_pong_streaming" + "ping" ], "ci_platforms": [ "windows", @@ -18896,31 +19122,7 @@ }, { "args": [ - "registered_call" - ], - "ci_platforms": [ - "windows", - "linux", - "posix" - ], - "cpu_cost": 1.0, - "exclude_configs": [], - "exclude_iomgrs": [ - "uv" - ], - "flaky": false, - "language": "c", - "name": "h2_oauth2_test", - "platforms": [ - "windows", - "linux", - "mac", - "posix" - ] - }, - { - "args": [ - "request_with_flags" + "ping_pong_streaming" ], "ci_platforms": [ "windows", @@ -18944,14 +19146,14 @@ }, { "args": [ - "request_with_payload" + "registered_call" ], "ci_platforms": [ "windows", "linux", "posix" ], - "cpu_cost": 0.1, + "cpu_cost": 1.0, "exclude_configs": [], "exclude_iomgrs": [ "uv" @@ -18968,14 +19170,14 @@ }, { "args": [ - "resource_quota_server" + "request_with_flags" ], "ci_platforms": [ "windows", "linux", "posix" ], - "cpu_cost": 1.0, + "cpu_cost": 0.1, "exclude_configs": [], "exclude_iomgrs": [ "uv" @@ -18992,7 +19194,55 @@ }, { "args": [ - "server_finishes_request" + "request_with_payload" + ], + "ci_platforms": [ + "windows", + "linux", + "posix" + ], + "cpu_cost": 0.1, + "exclude_configs": [], + "exclude_iomgrs": [ + "uv" + ], + "flaky": false, + "language": "c", + "name": "h2_oauth2_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "resource_quota_server" + ], + "ci_platforms": [ + "windows", + "linux", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [ + "uv" + ], + "flaky": false, + "language": "c", + "name": "h2_oauth2_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "server_finishes_request" ], "ci_platforms": [ "windows", @@ -19998,6 +20248,30 @@ "posix" ] }, + { + "args": [ + "payload_with_proxy_auth" + ], + "ci_platforms": [ + "windows", + "linux", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [ + "uv" + ], + "flaky": false, + "language": "c", + "name": "h2_proxy_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, { "args": [ "ping_pong_streaming" @@ -21126,6 +21400,30 @@ "posix" ] }, + { + "args": [ + "payload_with_proxy_auth" + ], + "ci_platforms": [ + "windows", + "linux", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [ + "uv" + ], + "flaky": false, + "language": "c", + "name": "h2_sockpair_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, { "args": [ "ping_pong_streaming" @@ -22230,6 +22528,30 @@ "posix" ] }, + { + "args": [ + "payload_with_proxy_auth" + ], + "ci_platforms": [ + "windows", + "linux", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [ + "uv" + ], + "flaky": false, + "language": "c", + "name": "h2_sockpair+trace_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, { "args": [ "ping_pong_streaming" @@ -23422,6 +23744,32 @@ "posix" ] }, + { + "args": [ + "payload_with_proxy_auth" + ], + "ci_platforms": [ + "windows", + "linux", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [ + "msan" + ], + "exclude_iomgrs": [ + "uv" + ], + "flaky": false, + "language": "c", + "name": "h2_sockpair_1byte_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, { "args": [ "ping_pong_streaming" @@ -24667,6 +25015,29 @@ "posix" ] }, + { + "args": [ + "payload_with_proxy_auth" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "language": "c", + "name": "h2_ssl_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, { "args": [ "ping" @@ -25936,6 +26307,29 @@ "posix" ] }, + { + "args": [ + "payload_with_proxy_auth" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "language": "c", + "name": "h2_ssl_cert_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, { "args": [ "ping" @@ -27070,6 +27464,30 @@ "posix" ] }, + { + "args": [ + "payload_with_proxy_auth" + ], + "ci_platforms": [ + "windows", + "linux", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [ + "uv" + ], + "flaky": false, + "language": "c", + "name": "h2_ssl_proxy_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, { "args": [ "ping_pong_streaming" @@ -28260,14 +28678,14 @@ }, { "args": [ - "ping" + "payload_with_proxy_auth" ], "ci_platforms": [ "linux", "mac", "posix" ], - "cpu_cost": 0.1, + "cpu_cost": 1.0, "exclude_configs": [], "exclude_iomgrs": [ "uv" @@ -28283,7 +28701,7 @@ }, { "args": [ - "ping_pong_streaming" + "ping" ], "ci_platforms": [ "linux", @@ -28306,30 +28724,7 @@ }, { "args": [ - "registered_call" - ], - "ci_platforms": [ - "linux", - "mac", - "posix" - ], - "cpu_cost": 1.0, - "exclude_configs": [], - "exclude_iomgrs": [ - "uv" - ], - "flaky": false, - "language": "c", - "name": "h2_uds_test", - "platforms": [ - "linux", - "mac", - "posix" - ] - }, - { - "args": [ - "request_with_flags" + "ping_pong_streaming" ], "ci_platforms": [ "linux", @@ -28352,14 +28747,14 @@ }, { "args": [ - "request_with_payload" + "registered_call" ], "ci_platforms": [ "linux", "mac", "posix" ], - "cpu_cost": 0.1, + "cpu_cost": 1.0, "exclude_configs": [], "exclude_iomgrs": [ "uv" @@ -28375,14 +28770,14 @@ }, { "args": [ - "resource_quota_server" + "request_with_flags" ], "ci_platforms": [ "linux", "mac", "posix" ], - "cpu_cost": 1.0, + "cpu_cost": 0.1, "exclude_configs": [], "exclude_iomgrs": [ "uv" @@ -28398,7 +28793,7 @@ }, { "args": [ - "server_finishes_request" + "request_with_payload" ], "ci_platforms": [ "linux", @@ -28421,14 +28816,14 @@ }, { "args": [ - "shutdown_finishes_calls" + "resource_quota_server" ], "ci_platforms": [ "linux", "mac", "posix" ], - "cpu_cost": 0.1, + "cpu_cost": 1.0, "exclude_configs": [], "exclude_iomgrs": [ "uv" @@ -28444,7 +28839,7 @@ }, { "args": [ - "shutdown_finishes_tags" + "server_finishes_request" ], "ci_platforms": [ "linux", @@ -28467,7 +28862,53 @@ }, { "args": [ - "simple_cacheable_request" + "shutdown_finishes_calls" + ], + "ci_platforms": [ + "linux", + "mac", + "posix" + ], + "cpu_cost": 0.1, + "exclude_configs": [], + "exclude_iomgrs": [ + "uv" + ], + "flaky": false, + "language": "c", + "name": "h2_uds_test", + "platforms": [ + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "shutdown_finishes_tags" + ], + "ci_platforms": [ + "linux", + "mac", + "posix" + ], + "cpu_cost": 0.1, + "exclude_configs": [], + "exclude_iomgrs": [ + "uv" + ], + "flaky": false, + "language": "c", + "name": "h2_uds_test", + "platforms": [ + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "simple_cacheable_request" ], "ci_platforms": [ "linux", @@ -29504,6 +29945,29 @@ "posix" ] }, + { + "args": [ + "payload_with_proxy_auth" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "language": "c", + "name": "h2_census_nosec_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, { "args": [ "ping" @@ -30750,6 +31214,29 @@ "posix" ] }, + { + "args": [ + "payload_with_proxy_auth" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "language": "c", + "name": "h2_compress_nosec_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, { "args": [ "ping" @@ -31854,6 +32341,29 @@ "posix" ] }, + { + "args": [ + "payload_with_proxy_auth" + ], + "ci_platforms": [ + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [ + "uv" + ], + "flaky": false, + "language": "c", + "name": "h2_fd_nosec_test", + "platforms": [ + "linux", + "mac", + "posix" + ] + }, { "args": [ "ping_pong_streaming" @@ -33054,6 +33564,29 @@ "posix" ] }, + { + "args": [ + "payload_with_proxy_auth" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "language": "c", + "name": "h2_full_nosec_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, { "args": [ "ping" @@ -34152,6 +34685,25 @@ "linux" ] }, + { + "args": [ + "payload_with_proxy_auth" + ], + "ci_platforms": [ + "linux" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [ + "uv" + ], + "flaky": false, + "language": "c", + "name": "h2_full+pipe_nosec_test", + "platforms": [ + "linux" + ] + }, { "args": [ "ping" @@ -35280,6 +35832,29 @@ "posix" ] }, + { + "args": [ + "payload_with_proxy_auth" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "language": "c", + "name": "h2_full+trace_nosec_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, { "args": [ "ping" @@ -36526,6 +37101,29 @@ "posix" ] }, + { + "args": [ + "payload_with_proxy_auth" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "language": "c", + "name": "h2_full+workarounds_nosec_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, { "args": [ "ping" @@ -37804,6 +38402,30 @@ "posix" ] }, + { + "args": [ + "payload_with_proxy_auth" + ], + "ci_platforms": [ + "windows", + "linux", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [ + "uv" + ], + "flaky": false, + "language": "c", + "name": "h2_http_proxy_nosec_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, { "args": [ "ping" @@ -39068,6 +39690,29 @@ "posix" ] }, + { + "args": [ + "payload_with_proxy_auth" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "language": "c", + "name": "h2_load_reporting_nosec_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, { "args": [ "ping" @@ -40178,6 +40823,30 @@ "posix" ] }, + { + "args": [ + "payload_with_proxy_auth" + ], + "ci_platforms": [ + "windows", + "linux", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [ + "uv" + ], + "flaky": false, + "language": "c", + "name": "h2_proxy_nosec_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, { "args": [ "ping_pong_streaming" @@ -41282,6 +41951,30 @@ "posix" ] }, + { + "args": [ + "payload_with_proxy_auth" + ], + "ci_platforms": [ + "windows", + "linux", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [ + "uv" + ], + "flaky": false, + "language": "c", + "name": "h2_sockpair_nosec_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, { "args": [ "ping_pong_streaming" @@ -42362,6 +43055,30 @@ "posix" ] }, + { + "args": [ + "payload_with_proxy_auth" + ], + "ci_platforms": [ + "windows", + "linux", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [ + "uv" + ], + "flaky": false, + "language": "c", + "name": "h2_sockpair+trace_nosec_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, { "args": [ "ping_pong_streaming" @@ -43528,6 +44245,32 @@ "posix" ] }, + { + "args": [ + "payload_with_proxy_auth" + ], + "ci_platforms": [ + "windows", + "linux", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [ + "msan" + ], + "exclude_iomgrs": [ + "uv" + ], + "flaky": false, + "language": "c", + "name": "h2_sockpair_1byte_nosec_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, { "args": [ "ping_pong_streaming" @@ -44723,6 +45466,29 @@ "posix" ] }, + { + "args": [ + "payload_with_proxy_auth" + ], + "ci_platforms": [ + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [ + "uv" + ], + "flaky": false, + "language": "c", + "name": "h2_uds_nosec_test", + "platforms": [ + "linux", + "mac", + "posix" + ] + }, { "args": [ "ping" diff --git a/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj b/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj index 4d02c880825..3a45ed619c0 100644 --- a/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj +++ b/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj @@ -227,6 +227,8 @@ + + diff --git a/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj.filters b/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj.filters index 89316bc535f..69bcf02b43d 100644 --- a/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj.filters +++ b/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj.filters @@ -115,6 +115,9 @@ test\core\end2end\tests + + test\core\end2end\tests + test\core\end2end\tests diff --git a/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj b/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj index 95731114523..fe1f6279805 100644 --- a/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj +++ b/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj @@ -229,6 +229,8 @@ + + diff --git a/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj.filters b/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj.filters index 7d02fc3fa07..255a76e107e 100644 --- a/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj.filters +++ b/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj.filters @@ -118,6 +118,9 @@ test\core\end2end\tests + + test\core\end2end\tests + test\core\end2end\tests From ad11680be7e33bb813073b79286e5ada0c5830f2 Mon Sep 17 00:00:00 2001 From: Yash Tibrewal Date: Wed, 19 Jul 2017 11:00:22 -0700 Subject: [PATCH 058/127] remove unnecessary code --- test/core/end2end/fixtures/h2_http_proxy.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/core/end2end/fixtures/h2_http_proxy.c b/test/core/end2end/fixtures/h2_http_proxy.c index f87036d52e2..817a9a0a094 100644 --- a/test/core/end2end/fixtures/h2_http_proxy.c +++ b/test/core/end2end/fixtures/h2_http_proxy.c @@ -53,9 +53,6 @@ static grpc_end2end_test_fixture chttp2_create_fixture_fullstack( const int server_port = grpc_pick_unused_port_or_die(); gpr_join_host_port(&ffd->server_addr, "localhost", server_port); - /*const grpc_arg *proxy_auth_arg = - grpc_channel_args_find(client_args, "test_uses_proxy_auth"); - ffd->proxy = grpc_end2end_http_proxy_create(proxy_args);*/ //If we are testing proxy auth, add the proxy auth arg to proxy channel args grpc_channel_args *proxy_args = NULL; const grpc_arg *proxy_auth_arg = grpc_channel_args_find( From e929547d48d645cb5fbf3cf0db1663435c899800 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 19 Jul 2017 15:58:40 -0700 Subject: [PATCH 059/127] Fix issues with Node Mac build --- binding.gyp | 60 ++++++++++++++++++++++++++-------- templates/binding.gyp.template | 45 ++++++++++++++++++------- 2 files changed, 79 insertions(+), 26 deletions(-) diff --git a/binding.gyp b/binding.gyp index d11a60a68af..705b8f22c0c 100644 --- a/binding.gyp +++ b/binding.gyp @@ -175,21 +175,27 @@ }], ['OS == "mac"', { 'xcode_settings': { - 'MACOSX_DEPLOYMENT_TARGET': '10.9' + 'OTHER_CFLAGS': [ + '-g', + '-Wall', + '-Wextra', + '-Werror', + '-Wno-long-long', + '-Wno-unused-parameter', + '-DOSATOMIC_USE_INLINED=1', + ], + 'OTHER_CPLUSPLUSFLAGS': [ + '-g', + '-Wall', + '-Wextra', + '-Werror', + '-Wno-long-long', + '-Wno-unused-parameter', + '-DOSATOMIC_USE_INLINED=1', + '-stdlib=libc++', + '-std=c++11' + ], }, - 'OTHER_CFLAGS': [ - '-g', - '-Wall', - '-Wextra', - '-Werror', - '-Wno-long-long', - '-Wno-unused-parameter', - '-DOSATOMIC_USE_INLINED=1', - ], - 'OTHER_CPLUSPLUSFLAGS': [ - '-stdlib=libc++', - '-std=c++11' - ], }] ] }, @@ -508,6 +514,13 @@ 'third_party/boringssl/ssl/tls_method.c', 'third_party/boringssl/ssl/tls_record.c', ], + 'conditions': [ + ['OS == "mac"', { + 'xcode_settings': { + 'MACOSX_DEPLOYMENT_TARGET': '10.9' + } + }] + ] }, ], }], @@ -626,6 +639,13 @@ 'src/core/lib/support/tmpfile_windows.c', 'src/core/lib/support/wrap_memcpy.c', ], + 'conditions': [ + ['OS == "mac"', { + 'xcode_settings': { + 'MACOSX_DEPLOYMENT_TARGET': '10.9' + } + }] + ] }, { 'target_name': 'grpc', @@ -889,6 +909,13 @@ 'src/core/ext/filters/workarounds/workaround_utils.c', 'src/core/plugin_registry/grpc_plugin_registry.c', ], + 'conditions': [ + ['OS == "mac"', { + 'xcode_settings': { + 'MACOSX_DEPLOYMENT_TARGET': '10.9' + } + }] + ] }, { 'include_dirs': [ @@ -914,6 +941,11 @@ 'ldflags': [ '-Wl,-wrap,memcpy' ] + }], + ['OS == "mac"', { + 'xcode_settings': { + 'MACOSX_DEPLOYMENT_TARGET': '10.9' + } }] ], "target_name": "grpc_node", diff --git a/templates/binding.gyp.template b/templates/binding.gyp.template index b7560fe7df5..b1e1374249d 100644 --- a/templates/binding.gyp.template +++ b/templates/binding.gyp.template @@ -165,19 +165,21 @@ }], ['OS == "mac"', { 'xcode_settings': { - 'MACOSX_DEPLOYMENT_TARGET': '10.9' + % if defaults['global'].get('CPPFLAGS', None) is not None: + 'OTHER_CFLAGS': [ + % for item in defaults['global'].get('CPPFLAGS').split(): + '${item}', + % endfor + ], + 'OTHER_CPLUSPLUSFLAGS': [ + % for item in defaults['global'].get('CPPFLAGS').split(): + '${item}', + % endfor + '-stdlib=libc++', + '-std=c++11' + ], + % endif }, - % if defaults['global'].get('CPPFLAGS', None) is not None: - 'OTHER_CFLAGS': [ - % for item in defaults['global'].get('CPPFLAGS').split(): - '${item}', - % endfor - ], - 'OTHER_CPLUSPLUSFLAGS': [ - '-stdlib=libc++', - '-std=c++11' - ], - % endif }] ] }, @@ -201,6 +203,13 @@ '${source}', % endfor ], + 'conditions': [ + ['OS == "mac"', { + 'xcode_settings': { + 'MACOSX_DEPLOYMENT_TARGET': '10.9' + } + }] + ] }, % endif % endfor @@ -282,6 +291,13 @@ '${source}', % endfor ], + 'conditions': [ + ['OS == "mac"', { + 'xcode_settings': { + 'MACOSX_DEPLOYMENT_TARGET': '10.9' + } + }] + ] }, % endif % endfor @@ -317,6 +333,11 @@ 'ldflags': [ '-Wl,-wrap,memcpy' ] + }], + ['OS == "mac"', { + 'xcode_settings': { + 'MACOSX_DEPLOYMENT_TARGET': '10.9' + } }] ], "target_name": "${module.name}", From f20bfaa491a9d8cd832fd6c67eae19b10567ecb5 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 19 Jul 2017 16:27:02 -0700 Subject: [PATCH 060/127] transport - Use macro for grpc header bytes size --- .../transport/chttp2/transport/chttp2_transport.c | 13 +++++++------ src/core/ext/transport/chttp2/transport/internal.h | 2 ++ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c index d6c2ce7b05c..07ff9923ff4 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c @@ -1351,8 +1351,8 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op, "fetching_send_message_finished"); } else { GPR_ASSERT(s->fetching_send_message == NULL); - uint8_t *frame_hdr = - grpc_slice_buffer_tiny_add(&s->flow_controlled_buffer, 5); + uint8_t *frame_hdr = grpc_slice_buffer_tiny_add( + &s->flow_controlled_buffer, GRPC_HEADER_SIZE_IN_BYTES); uint32_t flags = op_payload->send_message.send_message->flags; frame_hdr[0] = (flags & GRPC_WRITE_INTERNAL_COMPRESS) != 0; size_t len = op_payload->send_message.send_message->length; @@ -1444,8 +1444,8 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op, s->recv_message = op_payload->recv_message.recv_message; if (s->id != 0) { already_received = s->frame_storage.length; - incoming_byte_stream_update_flow_control(exec_ctx, t, s, 5, - already_received); + incoming_byte_stream_update_flow_control( + exec_ctx, t, s, GRPC_HEADER_SIZE_IN_BYTES, already_received); } grpc_chttp2_maybe_complete_recv_message(exec_ctx, t, s); } @@ -1680,7 +1680,8 @@ void grpc_chttp2_maybe_complete_recv_message(grpc_exec_ctx *exec_ctx, } if (!grpc_stream_decompress(s->stream_decompression_ctx, &s->unprocessed_incoming_frames_buffer, - &s->decompressed_data_buffer, NULL, 5, + &s->decompressed_data_buffer, NULL, + GRPC_HEADER_SIZE_IN_BYTES, &end_of_context)) { grpc_slice_buffer_reset_and_unref_internal(exec_ctx, &s->frame_storage); @@ -1754,7 +1755,7 @@ void grpc_chttp2_maybe_complete_recv_trailing_metadata(grpc_exec_ctx *exec_ctx, if (!grpc_stream_decompress(s->stream_decompression_ctx, &s->frame_storage, &s->unprocessed_incoming_frames_buffer, NULL, - 5, &end_of_context)) { + GRPC_HEADER_SIZE_IN_BYTES, &end_of_context)) { grpc_slice_buffer_reset_and_unref_internal(exec_ctx, &s->frame_storage); grpc_slice_buffer_reset_and_unref_internal( exec_ctx, &s->unprocessed_incoming_frames_buffer); diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h index 0f29b10d377..21858681a78 100644 --- a/src/core/ext/transport/chttp2/transport/internal.h +++ b/src/core/ext/transport/chttp2/transport/internal.h @@ -634,6 +634,8 @@ void grpc_chttp2_complete_closure_step(grpc_exec_ctx *exec_ctx, grpc_closure **pclosure, grpc_error *error, const char *desc); +#define GRPC_HEADER_SIZE_IN_BYTES 5 + #define GRPC_CHTTP2_CLIENT_CONNECT_STRING "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" #define GRPC_CHTTP2_CLIENT_CONNECT_STRLEN \ (sizeof(GRPC_CHTTP2_CLIENT_CONNECT_STRING) - 1) From 78d7125017951d17b4e9ee2b8d184c5beed65d7c Mon Sep 17 00:00:00 2001 From: Yash Tibrewal Date: Wed, 19 Jul 2017 16:33:16 -0700 Subject: [PATCH 061/127] Removing a few style issues --- .../ext/filters/client_channel/http_proxy.c | 44 +++++++++---- test/core/end2end/fixtures/h2_http_proxy.c | 7 +- .../end2end/fixtures/http_proxy_fixture.c | 66 +++++++++++++------ 3 files changed, 84 insertions(+), 33 deletions(-) diff --git a/src/core/ext/filters/client_channel/http_proxy.c b/src/core/ext/filters/client_channel/http_proxy.c index 1bd847b0dbc..a8a23ceb9ed 100644 --- a/src/core/ext/filters/client_channel/http_proxy.c +++ b/src/core/ext/filters/client_channel/http_proxy.c @@ -34,12 +34,19 @@ #include "src/core/lib/support/string.h" #include "src/core/lib/slice/b64.h" -static void grpc_get_http_proxy_server(grpc_exec_ctx* exec_ctx, - char **name_to_resolve, +/** + * Parses the 'http_proxy' env var and returns the proxy hostname to resolve or + * NULL on error. Also sets 'user_cred' if it is not NULL to user credentials + * if present in the 'http_proxy' env var. + */ +static char *grpc_get_http_proxy_server(grpc_exec_ctx* exec_ctx, char **user_cred) { - *name_to_resolve = NULL; + char *proxy_name = NULL; + if(user_cred != NULL) { + *user_cred = NULL; + } char* uri_str = gpr_getenv("http_proxy"); - if (uri_str == NULL) return; + if (uri_str == NULL) return NULL; grpc_uri* uri = grpc_uri_parse(exec_ctx, uri_str, false /* suppress_errors */); if (uri == NULL || uri->authority == NULL) { @@ -50,18 +57,33 @@ static void grpc_get_http_proxy_server(grpc_exec_ctx* exec_ctx, gpr_log(GPR_ERROR, "'%s' scheme not supported in proxy URI", uri->scheme); goto done; } - char *user_cred_end = strchr(uri->authority, '@'); - if (user_cred_end != NULL) { - *name_to_resolve = gpr_strdup(user_cred_end + 1); - *user_cred_end = '\0'; - *user_cred = gpr_strdup(uri->authority); + /* Split on '@' to separate user credentials from host */ + char **authority_strs = NULL; + size_t authority_nstrs; + gpr_string_split(uri->authority, "@", &authority_strs, &authority_nstrs); + GPR_ASSERT(authority_nstrs != 0); /* should have atleast 1 string */ + if(authority_nstrs == 1) { + /* User cred not present in authority */ + proxy_name = gpr_strdup(authority_strs[0]); + } else if(authority_nstrs == 2) { + /* User cred found */ + if(user_cred != NULL) { + *user_cred = gpr_strdup(authority_strs[0]); + } + proxy_name = gpr_strdup(authority_strs[1]); gpr_log(GPR_INFO, "userinfo found in proxy URI"); } else { - *name_to_resolve = gpr_strdup(uri->authority); + /* Bad authority */ + proxy_name = NULL; + } + for(size_t i = 0; i < authority_nstrs; i++) { + gpr_free(authority_strs[i]); } + gpr_free(authority_strs); done: gpr_free(uri_str); grpc_uri_destroy(uri); + return proxy_name; } static bool proxy_mapper_map_name(grpc_exec_ctx* exec_ctx, @@ -71,7 +93,7 @@ static bool proxy_mapper_map_name(grpc_exec_ctx* exec_ctx, char** name_to_resolve, grpc_channel_args** new_args) { char *user_cred = NULL; - grpc_get_http_proxy_server(exec_ctx, name_to_resolve, &user_cred); + *name_to_resolve = grpc_get_http_proxy_server(exec_ctx, &user_cred); if (*name_to_resolve == NULL) return false; grpc_uri* uri = grpc_uri_parse(exec_ctx, server_uri, false /* suppress_errors */); diff --git a/test/core/end2end/fixtures/h2_http_proxy.c b/test/core/end2end/fixtures/h2_http_proxy.c index 817a9a0a094..ce93c614dfa 100644 --- a/test/core/end2end/fixtures/h2_http_proxy.c +++ b/test/core/end2end/fixtures/h2_http_proxy.c @@ -53,11 +53,12 @@ static grpc_end2end_test_fixture chttp2_create_fixture_fullstack( const int server_port = grpc_pick_unused_port_or_die(); gpr_join_host_port(&ffd->server_addr, "localhost", server_port); - //If we are testing proxy auth, add the proxy auth arg to proxy channel args + /* If we are testing proxy auth, add the proxy auth arg to proxy channel args + */ grpc_channel_args *proxy_args = NULL; const grpc_arg *proxy_auth_arg = grpc_channel_args_find( client_args, GRPC_END2END_HTTP_PROXY_TEST_CONNECT_AUTH_PRESENT); - if(proxy_auth_arg) { + if(proxy_auth_arg != NULL) { proxy_args = grpc_channel_args_copy_and_add(NULL, proxy_auth_arg, 1); } ffd->proxy = grpc_end2end_http_proxy_create(proxy_args); @@ -77,7 +78,7 @@ void chttp2_init_client_fullstack(grpc_end2end_test_fixture *f, fullstack_fixture_data *ffd = f->fixture_data; char *proxy_uri; - // If testing for proxy auth, add credentials to proxy uri + /* If testing for proxy auth, add credentials to proxy uri */ if(grpc_channel_args_find( client_args, GRPC_END2END_HTTP_PROXY_TEST_CONNECT_AUTH_PRESENT) == NULL) { gpr_asprintf(&proxy_uri, "http://%s", diff --git a/test/core/end2end/fixtures/http_proxy_fixture.c b/test/core/end2end/fixtures/http_proxy_fixture.c index d69ed1a0866..239444e75fa 100644 --- a/test/core/end2end/fixtures/http_proxy_fixture.c +++ b/test/core/end2end/fixtures/http_proxy_fixture.c @@ -47,8 +47,9 @@ #include "src/core/lib/iomgr/tcp_client.h" #include "src/core/lib/iomgr/tcp_server.h" #include "src/core/lib/iomgr/timer.h" -#include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/slice/b64.h" +#include "src/core/lib/slice/slice_internal.h" +#include "src/core/lib/support/string.h" #include "test/core/util/port.h" struct grpc_end2end_http_proxy { @@ -306,6 +307,45 @@ static void on_server_connect_done(grpc_exec_ctx* exec_ctx, void* arg, &conn->on_write_response_done); } +/** + * Parses the proxy auth header value to check if it matches :- + * Basic + * Returns true if it matches, false otherwise + */ +static bool proxy_auth_header_matches(grpc_exec_ctx *exec_ctx, + char *proxy_auth_header_val) { + if(proxy_auth_header_val == NULL) { + return false; + } + char **auth_header_strs; + size_t auth_header_nstrs; + bool auth_header_matches = false; + // Split the auth header value on space + gpr_string_split(proxy_auth_header_val, " ", &auth_header_strs, + &auth_header_nstrs); + if(auth_header_nstrs != 2) { + goto done; + } + // Authentication type should be Basic + if(strcmp(auth_header_strs[0], "Basic") != 0) { + goto done; + } + // should match GRPC_END2END_HTTP_PROXY_TEST_CONNECT_CRED after decoding + grpc_slice decoded_slice = + grpc_base64_decode(exec_ctx, auth_header_strs[1], 0); + if(grpc_slice_str_cmp( + decoded_slice, GRPC_END2END_HTTP_PROXY_TEST_CONNECT_CRED) != 0) { + goto done; + } + auth_header_matches = true; +done: + for(size_t i = 0; i < auth_header_nstrs; i++) { + gpr_free(auth_header_strs[i]); + } + gpr_free(auth_header_strs); + return auth_header_matches; +} + // Callback to read the HTTP CONNECT request. // TODO(roth): Technically, for any of the failure modes handled by this // function, we should handle the error by returning an HTTP response to @@ -354,34 +394,22 @@ static void on_read_request_done(grpc_exec_ctx* exec_ctx, void* arg, GRPC_ERROR_UNREF(error); return; } - // If proxy auth is being used, check if the header is present + // If proxy auth is being used, check if the header is present and as expected if(grpc_channel_args_find( conn->proxy->channel_args, GRPC_END2END_HTTP_PROXY_TEST_CONNECT_AUTH_PRESENT) != NULL) { - bool found = false, failed = false; + bool auth_header_found = false; for(size_t i = 0; i < conn->http_request.hdr_count; i++) { if(strcmp(conn->http_request.hdrs[i].key, "Proxy-Authorization") == 0) { - found = true; - // Authentication type should be Basic - if(strncmp(conn->http_request.hdrs[i].value, "Basic", - strlen("Basic")) != 0) { - failed = true; - break; - } - // Check if encoded string is as expected - char *encoded_str_start = - strchr(conn->http_request.hdrs[i].value, ' ') + 1; - grpc_slice decoded_slice = - grpc_base64_decode(exec_ctx, encoded_str_start, 0); - if(grpc_slice_str_cmp( - decoded_slice, GRPC_END2END_HTTP_PROXY_TEST_CONNECT_CRED) != 0) { - failed = true; + if(!proxy_auth_header_matches( + exec_ctx, conn->http_request.hdrs[i].value)) { break; } + auth_header_found = true; break; } } - if(!found || failed) { + if(!auth_header_found) { const char *msg = "HTTP Connect could not verify authentication"; error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); proxy_connection_failed(exec_ctx, conn, true /* is_client */, From ab0d2d4e78d46ea37477d7d58e0b12e25b1e9886 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 19 Jul 2017 16:36:25 -0700 Subject: [PATCH 062/127] transport - Change ~(size_t)0 to macro MAX_SIZE_T --- src/core/ext/transport/chttp2/transport/chttp2_transport.c | 2 +- src/core/ext/transport/chttp2/transport/internal.h | 1 + src/core/ext/transport/chttp2/transport/writing.c | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c index 07ff9923ff4..41516ed91a6 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c @@ -2714,7 +2714,7 @@ static grpc_error *incoming_byte_stream_pull(grpc_exec_ctx *exec_ctx, if (!grpc_stream_decompress(s->stream_decompression_ctx, &s->unprocessed_incoming_frames_buffer, &s->decompressed_data_buffer, NULL, - ~(size_t)0, &end_of_context)) { + MAX_SIZE_T, &end_of_context)) { error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Stream decompression error."); return error; diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h index 21858681a78..0f05da262bf 100644 --- a/src/core/ext/transport/chttp2/transport/internal.h +++ b/src/core/ext/transport/chttp2/transport/internal.h @@ -635,6 +635,7 @@ void grpc_chttp2_complete_closure_step(grpc_exec_ctx *exec_ctx, grpc_error *error, const char *desc); #define GRPC_HEADER_SIZE_IN_BYTES 5 +#define MAX_SIZE_T (~(size_t)0) #define GRPC_CHTTP2_CLIENT_CONNECT_STRING "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" #define GRPC_CHTTP2_CLIENT_CONNECT_STRLEN \ diff --git a/src/core/ext/transport/chttp2/transport/writing.c b/src/core/ext/transport/chttp2/transport/writing.c index dd20ff61aeb..08babb73692 100644 --- a/src/core/ext/transport/chttp2/transport/writing.c +++ b/src/core/ext/transport/chttp2/transport/writing.c @@ -351,7 +351,7 @@ grpc_chttp2_begin_write_result grpc_chttp2_begin_write( s->uncompressed_data_size = s->flow_controlled_buffer.length; GPR_ASSERT(grpc_stream_compress( s->stream_compression_ctx, &s->flow_controlled_buffer, - &s->compressed_data_buffer, NULL, ~(size_t)0, + &s->compressed_data_buffer, NULL, MAX_SIZE_T, GRPC_STREAM_COMPRESSION_FLUSH_SYNC)); } } From 99b339289620905e182c603901524950eef40e63 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Wed, 19 Jul 2017 16:38:56 -0700 Subject: [PATCH 063/127] transport - Update comment --- src/core/ext/transport/chttp2/transport/internal.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h index 0f05da262bf..9fad6835167 100644 --- a/src/core/ext/transport/chttp2/transport/internal.h +++ b/src/core/ext/transport/chttp2/transport/internal.h @@ -520,9 +520,9 @@ struct grpc_chttp2_stream { grpc_chttp2_write_cb *finish_after_write; size_t sending_bytes; - /** Whether stream compression send is enabled or not */ + /** Whether stream compression send is enabled */ bool stream_compression_recv_enabled; - /** Whether stream compression recv is enabled or not */ + /** Whether stream compression recv is enabled */ bool stream_compression_send_enabled; /** Whether bytes stored in unprocessed_incoming_byte_stream is decompressed */ From 7cc30c1155805537e18affd13cc4b7e44c3927be Mon Sep 17 00:00:00 2001 From: Alexander Polcyn Date: Tue, 18 Jul 2017 23:19:24 -0700 Subject: [PATCH 064/127] add missing fields on server call context and improve robustness of finished calls --- src/ruby/lib/grpc/generic/active_call.rb | 14 +- src/ruby/lib/grpc/generic/rpc_server.rb | 1 + src/ruby/spec/generic/client_stub_spec.rb | 166 +++++++++++++++------- src/ruby/spec/generic/rpc_server_spec.rb | 145 +++++++++++++++++++ 4 files changed, 276 insertions(+), 50 deletions(-) diff --git a/src/ruby/lib/grpc/generic/active_call.rb b/src/ruby/lib/grpc/generic/active_call.rb index 4a748a4ac29..84c88871680 100644 --- a/src/ruby/lib/grpc/generic/active_call.rb +++ b/src/ruby/lib/grpc/generic/active_call.rb @@ -44,9 +44,9 @@ module GRPC include Core::TimeConsts include Core::CallOps extend Forwardable - attr_reader :deadline, :metadata_sent, :metadata_to_send + attr_reader :deadline, :metadata_sent, :metadata_to_send, :peer, :peer_cert def_delegators :@call, :cancel, :metadata, :write_flag, :write_flag=, - :peer, :peer_cert, :trailing_metadata, :status + :trailing_metadata, :status # client_invoke begins a client invocation. # @@ -105,8 +105,13 @@ module GRPC @input_stream_done = false @call_finished = false @call_finished_mu = Mutex.new + @client_call_executed = false @client_call_executed_mu = Mutex.new + + # set the peer now so that the accessor can still function + # after the server closes the call + @peer = call.peer end # Sends the initial metadata that has yet to be sent. @@ -541,6 +546,10 @@ module GRPC end end + def attach_peer_cert(peer_cert) + @peer_cert = peer_cert + end + private # To be called once the "input stream" has been completelly @@ -612,6 +621,7 @@ module GRPC # server client_streamer handlers. MultiReqView = view_class(:cancelled?, :deadline, :each_queued_msg, :each_remote_read, :metadata, :output_metadata, + :peer, :peer_cert, :send_initial_metadata, :metadata_to_send, :merge_metadata_to_send, diff --git a/src/ruby/lib/grpc/generic/rpc_server.rb b/src/ruby/lib/grpc/generic/rpc_server.rb index ef2cc0ce918..33b3cea1fc3 100644 --- a/src/ruby/lib/grpc/generic/rpc_server.rb +++ b/src/ruby/lib/grpc/generic/rpc_server.rb @@ -418,6 +418,7 @@ module GRPC metadata_received: true, started: false, metadata_to_send: connect_md) + c.attach_peer_cert(an_rpc.call.peer_cert) mth = an_rpc.method.to_sym [c, mth] end diff --git a/src/ruby/spec/generic/client_stub_spec.rb b/src/ruby/spec/generic/client_stub_spec.rb index 7b5e6a95a43..a8653e73cfd 100644 --- a/src/ruby/spec/generic/client_stub_spec.rb +++ b/src/ruby/spec/generic/client_stub_spec.rb @@ -37,7 +37,9 @@ include GRPC::Core::TimeConsts include GRPC::Core::CallOps # check that methods on a finished/closed call t crash -def check_op_view_of_finished_client_call_is_robust(op_view) +def check_op_view_of_finished_client_call(op_view, + expected_metadata, + expected_trailing_metadata) # use read_response_stream to try to iterate through # possible response stream fail('need something to attempt reads') unless block_given? @@ -48,21 +50,39 @@ def check_op_view_of_finished_client_call_is_robust(op_view) expect { op_view.start_call }.to raise_error(RuntimeError) + sanity_check_values_of_accessors(op_view, + expected_metadata, + expected_trailing_metadata) + expect do op_view.wait op_view.cancel - - op_view.metadata - op_view.trailing_metadata - op_view.status - - op_view.cancelled? - op_view.deadline - op_view.write_flag op_view.write_flag = 1 end.to_not raise_error end +def sanity_check_values_of_accessors(op_view, + expected_metadata, + expected_trailing_metadata) + expected_status = Struct::Status.new + expected_status.code = 0 + expected_status.details = 'OK' + expected_status.metadata = expected_trailing_metadata + + expect(op_view.status).to eq(expected_status) + expect(op_view.metadata).to eq(expected_metadata) + expect(op_view.trailing_metadata).to eq(expected_trailing_metadata) + + expect(op_view.cancelled?).to be(false) + expect(op_view.write_flag).to be(nil) + + # The deadline attribute of a call can be either + # a GRPC::Core::TimeSpec or a Time, which are mutually exclusive. + # TODO: fix so that the accessor always returns the same type. + expect(op_view.deadline.is_a?(GRPC::Core::TimeSpec) || + op_view.deadline.is_a?(Time)).to be(true) +end + describe 'ClientStub' do let(:noop) { proc { |x| x } } @@ -154,7 +174,7 @@ describe 'ClientStub' do server_port = create_test_server host = "localhost:#{server_port}" th = run_request_response(@sent_msg, @resp, @pass, - k1: 'v1', k2: 'v2') + expected_metadata: { k1: 'v1', k2: 'v2' }) stub = GRPC::ClientStub.new(host, :this_channel_is_insecure) expect(get_response(stub)).to eq(@resp) th.join @@ -261,8 +281,14 @@ describe 'ClientStub' do def run_op_view_metadata_test(run_start_call_first) server_port = create_test_server host = "localhost:#{server_port}" - th = run_request_response(@sent_msg, @resp, @pass, - k1: 'v1', k2: 'v2') + + @server_initial_md = { 'sk1' => 'sv1', 'sk2' => 'sv2' } + @server_trailing_md = { 'tk1' => 'tv1', 'tk2' => 'tv2' } + th = run_request_response( + @sent_msg, @resp, @pass, + expected_metadata: @metadata, + server_initial_md: @server_initial_md, + server_trailing_md: @server_trailing_md) stub = GRPC::ClientStub.new(host, :this_channel_is_insecure) expect( get_response(stub, @@ -272,12 +298,14 @@ describe 'ClientStub' do it 'sends metadata to the server ok when running start_call first' do run_op_view_metadata_test(true) - check_op_view_of_finished_client_call_is_robust(@op) { |r| p r } + check_op_view_of_finished_client_call( + @op, @server_initial_md, @server_trailing_md) { |r| p r } end it 'does not crash when used after the call has been finished' do run_op_view_metadata_test(false) - check_op_view_of_finished_client_call_is_robust(@op) { |r| p r } + check_op_view_of_finished_client_call( + @op, @server_initial_md, @server_trailing_md) { |r| p r } end end end @@ -300,7 +328,8 @@ describe 'ClientStub' do end it 'should send metadata to the server ok' do - th = run_client_streamer(@sent_msgs, @resp, @pass, **@metadata) + th = run_client_streamer(@sent_msgs, @resp, @pass, + expected_metadata: @metadata) expect(get_response(@stub)).to eq(@resp) th.join end @@ -347,7 +376,13 @@ describe 'ClientStub' do it_behaves_like 'client streaming' def run_op_view_metadata_test(run_start_call_first) - th = run_client_streamer(@sent_msgs, @resp, @pass, **@metadata) + @server_initial_md = { 'sk1' => 'sv1', 'sk2' => 'sv2' } + @server_trailing_md = { 'tk1' => 'tv1', 'tk2' => 'tv2' } + th = run_client_streamer( + @sent_msgs, @resp, @pass, + expected_metadata: @metadata, + server_initial_md: @server_initial_md, + server_trailing_md: @server_trailing_md) expect( get_response(@stub, run_start_call_first: run_start_call_first)).to eq(@resp) @@ -356,12 +391,14 @@ describe 'ClientStub' do it 'sends metadata to the server ok when running start_call first' do run_op_view_metadata_test(true) - check_op_view_of_finished_client_call_is_robust(@op) { |r| p r } + check_op_view_of_finished_client_call( + @op, @server_initial_md, @server_trailing_md) { |r| p r } end it 'does not crash when used after the call has been finished' do run_op_view_metadata_test(false) - check_op_view_of_finished_client_call_is_robust(@op) { |r| p r } + check_op_view_of_finished_client_call( + @op, @server_initial_md, @server_trailing_md) { |r| p r } end end end @@ -396,7 +433,7 @@ describe 'ClientStub' do server_port = create_test_server host = "localhost:#{server_port}" th = run_server_streamer(@sent_msg, @replys, @fail, - k1: 'v1', k2: 'v2') + expected_metadata: { k1: 'v1', k2: 'v2' }) stub = GRPC::ClientStub.new(host, :this_channel_is_insecure) e = get_responses(stub) expect { e.collect { |r| r } }.to raise_error(GRPC::BadStatus) @@ -459,24 +496,31 @@ describe 'ClientStub' do def run_op_view_metadata_test(run_start_call_first) server_port = create_test_server host = "localhost:#{server_port}" - th = run_server_streamer(@sent_msg, @replys, @fail, - k1: 'v1', k2: 'v2') + @server_initial_md = { 'sk1' => 'sv1', 'sk2' => 'sv2' } + @server_trailing_md = { 'tk1' => 'tv1', 'tk2' => 'tv2' } + th = run_server_streamer( + @sent_msg, @replys, @pass, + expected_metadata: @metadata, + server_initial_md: @server_initial_md, + server_trailing_md: @server_trailing_md) stub = GRPC::ClientStub.new(host, :this_channel_is_insecure) e = get_responses(stub, run_start_call_first: run_start_call_first) - expect { e.collect { |r| r } }.to raise_error(GRPC::BadStatus) + expect(e.collect { |r| r }).to eq(@replys) th.join end it 'should send metadata to the server ok when start_call is run first' do run_op_view_metadata_test(true) - check_op_view_of_finished_client_call_is_robust(@op) do |responses| + check_op_view_of_finished_client_call( + @op, @server_initial_md, @server_trailing_md) do |responses| responses.each { |r| p r } end end it 'does not crash when used after the call has been finished' do run_op_view_metadata_test(false) - check_op_view_of_finished_client_call_is_robust(@op) do |responses| + check_op_view_of_finished_client_call( + @op, @server_initial_md, @server_trailing_md) do |responses| responses.each { |r| p r } end end @@ -530,7 +574,7 @@ describe 'ClientStub' do it 'should send metadata to the server ok' do th = run_bidi_streamer_echo_ping_pong(@sent_msgs, @pass, true, - **@metadata) + expected_metadata: @metadata) stub = GRPC::ClientStub.new(@host, :this_channel_is_insecure) e = get_responses(stub) expect(e.collect { |r| r }).to eq(@sent_msgs) @@ -567,40 +611,52 @@ describe 'ClientStub' do it_behaves_like 'bidi streaming' def run_op_view_metadata_test(run_start_call_first) - th = run_bidi_streamer_handle_inputs_first(@sent_msgs, @replys, - @pass) + @server_initial_md = { 'sk1' => 'sv1', 'sk2' => 'sv2' } + @server_trailing_md = { 'tk1' => 'tv1', 'tk2' => 'tv2' } + th = run_bidi_streamer_echo_ping_pong( + @sent_msgs, @pass, true, + expected_metadata: @metadata, + server_initial_md: @server_initial_md, + server_trailing_md: @server_trailing_md) stub = GRPC::ClientStub.new(@host, :this_channel_is_insecure) e = get_responses(stub, run_start_call_first: run_start_call_first) - expect(e.collect { |r| r }).to eq(@replys) + expect(e.collect { |r| r }).to eq(@sent_msgs) th.join end it 'can run start_call before executing the call' do run_op_view_metadata_test(true) - check_op_view_of_finished_client_call_is_robust(@op) do |responses| + check_op_view_of_finished_client_call( + @op, @server_initial_md, @server_trailing_md) do |responses| responses.each { |r| p r } end end it 'doesnt crash when op_view used after call has finished' do run_op_view_metadata_test(false) - check_op_view_of_finished_client_call_is_robust(@op) do |responses| + check_op_view_of_finished_client_call( + @op, @server_initial_md, @server_trailing_md) do |responses| responses.each { |r| p r } end end end end - def run_server_streamer(expected_input, replys, status, **kw) - wanted_metadata = kw.clone + def run_server_streamer(expected_input, replys, status, + expected_metadata: {}, + server_initial_md: {}, + server_trailing_md: {}) + wanted_metadata = expected_metadata.clone wakey_thread do |notifier| - c = expect_server_to_be_invoked(notifier) + c = expect_server_to_be_invoked( + notifier, metadata_to_send: server_initial_md) wanted_metadata.each do |k, v| expect(c.metadata[k.to_s]).to eq(v) end expect(c.remote_read).to eq(expected_input) replys.each { |r| c.remote_send(r) } - c.send_status(status, status == @pass ? 'OK' : 'NOK', true) + c.send_status(status, status == @pass ? 'OK' : 'NOK', true, + metadata: server_trailing_md) end end @@ -615,10 +671,13 @@ describe 'ClientStub' do end def run_bidi_streamer_echo_ping_pong(expected_inputs, status, client_starts, - **kw) - wanted_metadata = kw.clone + expected_metadata: {}, + server_initial_md: {}, + server_trailing_md: {}) + wanted_metadata = expected_metadata.clone wakey_thread do |notifier| - c = expect_server_to_be_invoked(notifier) + c = expect_server_to_be_invoked( + notifier, metadata_to_send: server_initial_md) wanted_metadata.each do |k, v| expect(c.metadata[k.to_s]).to eq(v) end @@ -631,33 +690,44 @@ describe 'ClientStub' do expect(c.remote_read).to eq(i) end end - c.send_status(status, status == @pass ? 'OK' : 'NOK', true) + c.send_status(status, status == @pass ? 'OK' : 'NOK', true, + metadata: server_trailing_md) end end - def run_client_streamer(expected_inputs, resp, status, **kw) - wanted_metadata = kw.clone + def run_client_streamer(expected_inputs, resp, status, + expected_metadata: {}, + server_initial_md: {}, + server_trailing_md: {}) + wanted_metadata = expected_metadata.clone wakey_thread do |notifier| - c = expect_server_to_be_invoked(notifier) + c = expect_server_to_be_invoked( + notifier, metadata_to_send: server_initial_md) expected_inputs.each { |i| expect(c.remote_read).to eq(i) } wanted_metadata.each do |k, v| expect(c.metadata[k.to_s]).to eq(v) end c.remote_send(resp) - c.send_status(status, status == @pass ? 'OK' : 'NOK', true) + c.send_status(status, status == @pass ? 'OK' : 'NOK', true, + metadata: server_trailing_md) end end - def run_request_response(expected_input, resp, status, **kw) - wanted_metadata = kw.clone + def run_request_response(expected_input, resp, status, + expected_metadata: {}, + server_initial_md: {}, + server_trailing_md: {}) + wanted_metadata = expected_metadata.clone wakey_thread do |notifier| - c = expect_server_to_be_invoked(notifier) + c = expect_server_to_be_invoked( + notifier, metadata_to_send: server_initial_md) expect(c.remote_read).to eq(expected_input) wanted_metadata.each do |k, v| expect(c.metadata[k.to_s]).to eq(v) end c.remote_send(resp) - c.send_status(status, status == @pass ? 'OK' : 'NOK', true) + c.send_status(status, status == @pass ? 'OK' : 'NOK', true, + metadata: server_trailing_md) end end @@ -675,13 +745,13 @@ describe 'ClientStub' do @server.add_http2_port('0.0.0.0:0', :this_port_is_insecure) end - def expect_server_to_be_invoked(notifier) + def expect_server_to_be_invoked(notifier, metadata_to_send: nil) @server.start notifier.notify(nil) recvd_rpc = @server.request_call recvd_call = recvd_rpc.call recvd_call.metadata = recvd_rpc.metadata - recvd_call.run_batch(SEND_INITIAL_METADATA => nil) + recvd_call.run_batch(SEND_INITIAL_METADATA => metadata_to_send) GRPC::ActiveCall.new(recvd_call, noop, noop, INFINITE_FUTURE, metadata_received: true) end diff --git a/src/ruby/spec/generic/rpc_server_spec.rb b/src/ruby/spec/generic/rpc_server_spec.rb index 9633a828a2a..4258d59851d 100644 --- a/src/ruby/spec/generic/rpc_server_spec.rb +++ b/src/ruby/spec/generic/rpc_server_spec.rb @@ -111,6 +111,47 @@ end SlowStub = SlowService.rpc_stub_class +# a test service that hangs onto call objects +# and uses them after the server-side call has been +# finished +class CheckCallAfterFinishedService + include GRPC::GenericService + rpc :an_rpc, EchoMsg, EchoMsg + rpc :a_client_streaming_rpc, stream(EchoMsg), EchoMsg + rpc :a_server_streaming_rpc, EchoMsg, stream(EchoMsg) + rpc :a_bidi_rpc, stream(EchoMsg), stream(EchoMsg) + attr_reader :server_side_call + + def an_rpc(req, call) + fail 'shouldnt reuse service' unless @call.nil? + @server_side_call = call + req + end + + def a_client_streaming_rpc(call) + fail 'shouldnt reuse service' unless @call.nil? + @server_side_call = call + # iterate through requests so call can complete + call.each_remote_read.each { |r| p r } + EchoMsg.new + end + + def a_server_streaming_rpc(_, call) + fail 'shouldnt reuse service' unless @call.nil? + @server_side_call = call + [EchoMsg.new, EchoMsg.new] + end + + def a_bidi_rpc(requests, call) + fail 'shouldnt reuse service' unless @call.nil? + @server_side_call = call + requests.each { |r| p r } + [EchoMsg.new, EchoMsg.new] + end +end + +CheckCallAfterFinishedServiceStub = CheckCallAfterFinishedService.rpc_stub_class + describe GRPC::RpcServer do RpcServer = GRPC::RpcServer StatusCodes = GRPC::Core::StatusCodes @@ -505,5 +546,109 @@ describe GRPC::RpcServer do t.join end end + + context 'when call objects are used after calls have completed' do + before(:each) do + server_opts = { + poll_period: 1 + } + @srv = RpcServer.new(**server_opts) + alt_port = @srv.add_http2_port('0.0.0.0:0', :this_port_is_insecure) + @alt_host = "0.0.0.0:#{alt_port}" + + @service = CheckCallAfterFinishedService.new + @srv.handle(@service) + @srv_thd = Thread.new { @srv.run } + @srv.wait_till_running + end + + # check that the server-side call is still in a usable state even + # after it has finished + def check_single_req_view_of_finished_call(call) + common_check_of_finished_server_call(call) + + expect(call.peer).to be_a(String) + expect(call.peer_cert).to be(nil) + end + + def check_multi_req_view_of_finished_call(call) + common_check_of_finished_server_call(call) + + expect do + call.each_remote_read.each { |r| p r } + end.to raise_error(GRPC::Core::CallError) + end + + def common_check_of_finished_server_call(call) + expect do + call.merge_metadata_to_send({}) + end.to raise_error(RuntimeError) + + expect do + call.send_initial_metadata + end.to_not raise_error + + expect(call.cancelled?).to be(false) + expect(call.metadata).to be_a(Hash) + expect(call.metadata['user-agent']).to be_a(String) + + expect(call.metadata_sent).to be(true) + expect(call.output_metadata).to eq({}) + expect(call.metadata_to_send).to eq({}) + expect(call.deadline.is_a?(Time)).to be(true) + end + + it 'should not crash when call used after an unary call is finished' do + req = EchoMsg.new + stub = CheckCallAfterFinishedServiceStub.new(@alt_host, + :this_channel_is_insecure) + resp = stub.an_rpc(req) + expect(resp).to be_a(EchoMsg) + @srv.stop + @srv_thd.join + + check_single_req_view_of_finished_call(@service.server_side_call) + end + + it 'should not crash when call used after client streaming finished' do + requests = [EchoMsg.new, EchoMsg.new] + stub = CheckCallAfterFinishedServiceStub.new(@alt_host, + :this_channel_is_insecure) + resp = stub.a_client_streaming_rpc(requests) + expect(resp).to be_a(EchoMsg) + @srv.stop + @srv_thd.join + + check_multi_req_view_of_finished_call(@service.server_side_call) + end + + it 'should not crash when call used after server streaming finished' do + req = EchoMsg.new + stub = CheckCallAfterFinishedServiceStub.new(@alt_host, + :this_channel_is_insecure) + responses = stub.a_server_streaming_rpc(req) + responses.each do |r| + expect(r).to be_a(EchoMsg) + end + @srv.stop + @srv_thd.join + + check_single_req_view_of_finished_call(@service.server_side_call) + end + + it 'should not crash when call used after a bidi call is finished' do + requests = [EchoMsg.new, EchoMsg.new] + stub = CheckCallAfterFinishedServiceStub.new(@alt_host, + :this_channel_is_insecure) + responses = stub.a_bidi_rpc(requests) + responses.each do |r| + expect(r).to be_a(EchoMsg) + end + @srv.stop + @srv_thd.join + + check_multi_req_view_of_finished_call(@service.server_side_call) + end + end end end From a74ea8602d60bfdf4d99642e6c72573b803e69dc Mon Sep 17 00:00:00 2001 From: Yash Tibrewal Date: Wed, 19 Jul 2017 17:43:30 -0700 Subject: [PATCH 065/127] Nit correction --- src/core/ext/filters/client_channel/http_proxy.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/ext/filters/client_channel/http_proxy.c b/src/core/ext/filters/client_channel/http_proxy.c index a8a23ceb9ed..2e2471e68d6 100644 --- a/src/core/ext/filters/client_channel/http_proxy.c +++ b/src/core/ext/filters/client_channel/http_proxy.c @@ -36,8 +36,8 @@ /** * Parses the 'http_proxy' env var and returns the proxy hostname to resolve or - * NULL on error. Also sets 'user_cred' if it is not NULL to user credentials - * if present in the 'http_proxy' env var. + * NULL on error. Also sets 'user_cred' to user credentials present in the + * 'http_proxy' env var, NULL if not present. */ static char *grpc_get_http_proxy_server(grpc_exec_ctx* exec_ctx, char **user_cred) { @@ -61,7 +61,7 @@ static char *grpc_get_http_proxy_server(grpc_exec_ctx* exec_ctx, char **authority_strs = NULL; size_t authority_nstrs; gpr_string_split(uri->authority, "@", &authority_strs, &authority_nstrs); - GPR_ASSERT(authority_nstrs != 0); /* should have atleast 1 string */ + GPR_ASSERT(authority_nstrs != 0); /* should have at least 1 string */ if(authority_nstrs == 1) { /* User cred not present in authority */ proxy_name = gpr_strdup(authority_strs[0]); From 0c22cad01fe778ca2df217c7ef2a68dfac24254d Mon Sep 17 00:00:00 2001 From: Vijay Pai Date: Thu, 20 Jul 2017 10:33:52 -0700 Subject: [PATCH 066/127] Improve a comment in inproc transport --- src/core/ext/transport/inproc/inproc_transport.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/core/ext/transport/inproc/inproc_transport.c b/src/core/ext/transport/inproc/inproc_transport.c index 4df64d81e2b..14498021ebd 100644 --- a/src/core/ext/transport/inproc/inproc_transport.c +++ b/src/core/ext/transport/inproc/inproc_transport.c @@ -190,8 +190,11 @@ typedef struct inproc_stream { static bool inproc_slice_byte_stream_next(grpc_exec_ctx *exec_ctx, grpc_byte_stream *bs, size_t max, grpc_closure *on_complete) { - inproc_slice_byte_stream *stream = (inproc_slice_byte_stream *)bs; - return (stream->le->sb.count != 0); + // Because inproc transport always provides the entire message atomically, + // the byte stream always has data available when this function is called. + // Thus, this function always returns true (unlike other transports) and + // there is never any need to schedule a closure + return true; } static grpc_error *inproc_slice_byte_stream_pull(grpc_exec_ctx *exec_ctx, From 655c8b10f647c339cbc54afb8dfde95980d303e7 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 20 Jul 2017 10:23:43 -0700 Subject: [PATCH 067/127] Fix Node build for older versions of Electron on Mac --- binding.gyp | 3 ++- templates/binding.gyp.template | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/binding.gyp b/binding.gyp index 705b8f22c0c..d5902cc68f0 100644 --- a/binding.gyp +++ b/binding.gyp @@ -193,7 +193,8 @@ '-Wno-unused-parameter', '-DOSATOMIC_USE_INLINED=1', '-stdlib=libc++', - '-std=c++11' + '-std=c++11', + '-Wno-error=deprecated-declarations' ], }, }] diff --git a/templates/binding.gyp.template b/templates/binding.gyp.template index b1e1374249d..adb7d9f7746 100644 --- a/templates/binding.gyp.template +++ b/templates/binding.gyp.template @@ -176,7 +176,8 @@ '${item}', % endfor '-stdlib=libc++', - '-std=c++11' + '-std=c++11', + '-Wno-error=deprecated-declarations' ], % endif }, From a858990b227055a8a1f61fb139952d85b8ab55b9 Mon Sep 17 00:00:00 2001 From: Adele Zhou Date: Thu, 20 Jul 2017 14:29:39 -0700 Subject: [PATCH 068/127] Update perf link. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0edea885185..995f877219c 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ See [INSTALL](INSTALL.md) for installation instructions for various platforms. See [tools/run_tests](tools/run_tests) for more guidance on how to run various test suites (e.g. unit tests, interop tests, benchmarks) -See [Performance dashboard](http://performance-dot-grpc-testing.appspot.com/explore?dashboard=5712453606309888) for the performance numbers for v1.0.x. +See [Performance dashboard](http://performance-dot-grpc-testing.appspot.com/explore?dashboard=5636470266134528) for the performance numbers for the latest released version. # Repository Structure & Status From 5c92dcde1ee0c25a3c341c88af62fec600645252 Mon Sep 17 00:00:00 2001 From: ncteisen Date: Thu, 20 Jul 2017 14:55:49 -0700 Subject: [PATCH 069/127] Allow passing regex to bm_diff tools --- .../microbenchmarks/bm_diff/bm_diff.py | 5 +++-- .../microbenchmarks/bm_diff/bm_main.py | 14 ++++++------- .../microbenchmarks/bm_diff/bm_run.py | 21 +++++++++---------- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/tools/profiling/microbenchmarks/bm_diff/bm_diff.py b/tools/profiling/microbenchmarks/bm_diff/bm_diff.py index 809817a1a8c..1ac951f3d86 100755 --- a/tools/profiling/microbenchmarks/bm_diff/bm_diff.py +++ b/tools/profiling/microbenchmarks/bm_diff/bm_diff.py @@ -144,7 +144,7 @@ def _read_json(filename, badjson_files, nonexistant_files): def fmt_dict(d): return ''.join([" " + k + ": " + str(d[k]) + "\n" for k in d]) -def diff(bms, loops, track, old, new, counters): +def diff(bms, loops, regex, track, old, new, counters): benchmarks = collections.defaultdict(Benchmark) badjson_files = {} @@ -153,7 +153,8 @@ def diff(bms, loops, track, old, new, counters): for loop in range(0, loops): for line in subprocess.check_output( ['bm_diff_%s/opt/%s' % (old, bm), - '--benchmark_list_tests']).splitlines(): + '--benchmark_list_tests', + '--benchmark_filter=%s' % regex]).splitlines(): stripped_line = line.strip().replace("/", "_").replace( "<", "_").replace(">", "_").replace(", ", "_") js_new_opt = _read_json('%s.%s.opt.%s.%d.json' % diff --git a/tools/profiling/microbenchmarks/bm_diff/bm_main.py b/tools/profiling/microbenchmarks/bm_diff/bm_main.py index 8b4e0cb69a4..5aa11ac391e 100755 --- a/tools/profiling/microbenchmarks/bm_diff/bm_main.py +++ b/tools/profiling/microbenchmarks/bm_diff/bm_main.py @@ -63,10 +63,10 @@ def _args(): help='Name of baseline run to compare to. Ususally just called "old"') argp.add_argument( '-r', - '--repetitions', - type=int, - default=1, - help='Number of repetitions to pass to the benchmarks') + '--regex', + type=str, + default="", + help='Regex to filter benchmarks run') argp.add_argument( '-l', '--loops', @@ -125,10 +125,10 @@ def main(args): subprocess.check_call(['git', 'checkout', where_am_i]) subprocess.check_call(['git', 'submodule', 'update']) - bm_run.run('new', args.benchmarks, args.jobs, args.loops, args.repetitions, args.counters) - bm_run.run(old, args.benchmarks, args.jobs, args.loops, args.repetitions, args.counters) + bm_run.run('new', args.benchmarks, args.jobs, args.loops, args.regex, args.counters) + bm_run.run(old, args.benchmarks, args.jobs, args.loops, args.regex, args.counters) - diff, note = bm_diff.diff(args.benchmarks, args.loops, args.track, old, + diff, note = bm_diff.diff(args.benchmarks, args.loops, args.regex, args.track, old, 'new', args.counters) if diff: text = '[%s] Performance differences noted:\n%s' % (args.pr_comment_name, diff) diff --git a/tools/profiling/microbenchmarks/bm_diff/bm_run.py b/tools/profiling/microbenchmarks/bm_diff/bm_run.py index 72b3d3cf106..206f7c5845f 100755 --- a/tools/profiling/microbenchmarks/bm_diff/bm_run.py +++ b/tools/profiling/microbenchmarks/bm_diff/bm_run.py @@ -56,10 +56,10 @@ def _args(): ) argp.add_argument( '-r', - '--repetitions', - type=int, - default=1, - help='Number of repetitions to pass to the benchmarks') + '--regex', + type=str, + default="", + help='Regex to filter benchmarks run') argp.add_argument( '-l', '--loops', @@ -77,18 +77,17 @@ def _args(): return args -def _collect_bm_data(bm, cfg, name, reps, idx, loops): +def _collect_bm_data(bm, cfg, name, regex, idx, loops): jobs_list = [] for line in subprocess.check_output( ['bm_diff_%s/%s/%s' % (name, cfg, bm), - '--benchmark_list_tests']).splitlines(): + '--benchmark_list_tests', '--benchmark_filter=%s' % regex]).splitlines(): stripped_line = line.strip().replace("/", "_").replace( "<", "_").replace(">", "_").replace(", ", "_") cmd = [ 'bm_diff_%s/%s/%s' % (name, cfg, bm), '--benchmark_filter=^%s$' % line, '--benchmark_out=%s.%s.%s.%s.%d.json' % (bm, stripped_line, cfg, name, idx), '--benchmark_out_format=json', - '--benchmark_repetitions=%d' % (reps) ] jobs_list.append( jobset.JobSpec( @@ -100,13 +99,13 @@ def _collect_bm_data(bm, cfg, name, reps, idx, loops): return jobs_list -def run(name, benchmarks, jobs, loops, reps, counters): +def run(name, benchmarks, jobs, loops, regex, counters): jobs_list = [] for loop in range(0, loops): for bm in benchmarks: - jobs_list += _collect_bm_data(bm, 'opt', name, reps, loop, loops) + jobs_list += _collect_bm_data(bm, 'opt', name, regex, loop, loops) if counters: - jobs_list += _collect_bm_data(bm, 'counters', name, reps, loop, + jobs_list += _collect_bm_data(bm, 'counters', name, regex, loop, loops) random.shuffle(jobs_list, random.SystemRandom().random) jobset.run(jobs_list, maxjobs=jobs) @@ -114,4 +113,4 @@ def run(name, benchmarks, jobs, loops, reps, counters): if __name__ == '__main__': args = _args() - run(args.name, args.benchmarks, args.jobs, args.loops, args.repetitions, args.counters) + run(args.name, args.benchmarks, args.jobs, args.loops, args.regex, args.counters) From 7cc83e0701aafb2cc2412796b72bddbfbda4eac4 Mon Sep 17 00:00:00 2001 From: Alexander Polcyn Date: Wed, 19 Jul 2017 17:39:04 -0700 Subject: [PATCH 070/127] add a standalone client auth test --- src/ruby/spec/client_auth_spec.rb | 137 +++++++++++++++++++++++ src/ruby/spec/generic/rpc_server_spec.rb | 8 +- src/ruby/spec/testdata/client.key | 16 +++ src/ruby/spec/testdata/client.pem | 14 +++ 4 files changed, 171 insertions(+), 4 deletions(-) create mode 100644 src/ruby/spec/client_auth_spec.rb create mode 100644 src/ruby/spec/testdata/client.key create mode 100644 src/ruby/spec/testdata/client.pem diff --git a/src/ruby/spec/client_auth_spec.rb b/src/ruby/spec/client_auth_spec.rb new file mode 100644 index 00000000000..79c9192aa5f --- /dev/null +++ b/src/ruby/spec/client_auth_spec.rb @@ -0,0 +1,137 @@ +# Copyright 2015 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require 'grpc' + +def create_channel_creds + test_root = File.join(File.dirname(__FILE__), 'testdata') + files = ['ca.pem', 'client.key', 'client.pem'] + creds = files.map { |f| File.open(File.join(test_root, f)).read } + GRPC::Core::ChannelCredentials.new(creds[0], creds[1], creds[2]) +end + +def client_cert + test_root = File.join(File.dirname(__FILE__), 'testdata') + cert = File.open(File.join(test_root, 'client.pem')).read + fail unless cert.is_a?(String) + cert +end + +def create_server_creds + test_root = File.join(File.dirname(__FILE__), 'testdata') + p "test root: #{test_root}" + files = ['ca.pem', 'server1.key', 'server1.pem'] + creds = files.map { |f| File.open(File.join(test_root, f)).read } + GRPC::Core::ServerCredentials.new( + creds[0], + [{ private_key: creds[1], cert_chain: creds[2] }], + true) # force client auth +end + +# A test message +class EchoMsg + def self.marshal(_o) + '' + end + + def self.unmarshal(_o) + EchoMsg.new + end +end + +# a test service that checks the cert of its peer +class SslTestService + include GRPC::GenericService + rpc :an_rpc, EchoMsg, EchoMsg + rpc :a_client_streaming_rpc, stream(EchoMsg), EchoMsg + rpc :a_server_streaming_rpc, EchoMsg, stream(EchoMsg) + rpc :a_bidi_rpc, stream(EchoMsg), stream(EchoMsg) + + def check_peer_cert(call) + error_msg = "want:\n#{client_cert}\n\ngot:\n#{call.peer_cert}" + fail(error_msg) unless call.peer_cert == client_cert + end + + def an_rpc(req, call) + check_peer_cert(call) + req + end + + def a_client_streaming_rpc(call) + check_peer_cert(call) + call.each_remote_read.each { |r| p r } + EchoMsg.new + end + + def a_server_streaming_rpc(_, call) + check_peer_cert(call) + [EchoMsg.new, EchoMsg.new] + end + + def a_bidi_rpc(requests, call) + check_peer_cert(call) + requests.each { |r| p r } + [EchoMsg.new, EchoMsg.new] + end +end + +SslTestServiceStub = SslTestService.rpc_stub_class + +describe 'client-server auth' do + RpcServer = GRPC::RpcServer + + before(:all) do + server_opts = { + poll_period: 1 + } + @srv = RpcServer.new(**server_opts) + port = @srv.add_http2_port('0.0.0.0:0', create_server_creds) + @srv.handle(SslTestService) + @srv_thd = Thread.new { @srv.run } + @srv.wait_till_running + + client_opts = { + channel_args: { + GRPC::Core::Channel::SSL_TARGET => 'foo.test.google.fr' + } + } + @stub = SslTestServiceStub.new("localhost:#{port}", + create_channel_creds, + **client_opts) + end + + after(:all) do + expect(@srv.stopped?).to be(false) + @srv.stop + @srv_thd.join + end + + it 'client-server auth with unary RPCs' do + @stub.an_rpc(EchoMsg.new) + end + + it 'client-server auth with client streaming RPCs' do + @stub.a_client_streaming_rpc([EchoMsg.new, EchoMsg.new]) + end + + it 'client-server auth with server streaming RPCs' do + responses = @stub.a_server_streaming_rpc(EchoMsg.new) + responses.each { |r| p r } + end + + it 'client-server auth with bidi RPCs' do + responses = @stub.a_bidi_rpc([EchoMsg.new, EchoMsg.new]) + responses.each { |r| p r } + end +end diff --git a/src/ruby/spec/generic/rpc_server_spec.rb b/src/ruby/spec/generic/rpc_server_spec.rb index 4258d59851d..e0646f45997 100644 --- a/src/ruby/spec/generic/rpc_server_spec.rb +++ b/src/ruby/spec/generic/rpc_server_spec.rb @@ -123,13 +123,13 @@ class CheckCallAfterFinishedService attr_reader :server_side_call def an_rpc(req, call) - fail 'shouldnt reuse service' unless @call.nil? + fail 'shouldnt reuse service' unless @server_side_call.nil? @server_side_call = call req end def a_client_streaming_rpc(call) - fail 'shouldnt reuse service' unless @call.nil? + fail 'shouldnt reuse service' unless @server_side_call.nil? @server_side_call = call # iterate through requests so call can complete call.each_remote_read.each { |r| p r } @@ -137,13 +137,13 @@ class CheckCallAfterFinishedService end def a_server_streaming_rpc(_, call) - fail 'shouldnt reuse service' unless @call.nil? + fail 'shouldnt reuse service' unless @server_side_call.nil? @server_side_call = call [EchoMsg.new, EchoMsg.new] end def a_bidi_rpc(requests, call) - fail 'shouldnt reuse service' unless @call.nil? + fail 'shouldnt reuse service' unless @server_side_call.nil? @server_side_call = call requests.each { |r| p r } [EchoMsg.new, EchoMsg.new] diff --git a/src/ruby/spec/testdata/client.key b/src/ruby/spec/testdata/client.key new file mode 100644 index 00000000000..f48d0735d99 --- /dev/null +++ b/src/ruby/spec/testdata/client.key @@ -0,0 +1,16 @@ +-----BEGIN PRIVATE KEY----- +MIICeQIBADANBgkqhkiG9w0BAQEFAASCAmMwggJfAgEAAoGBAOxUR9uhvhbeVUIM +s5WbH0px0mehl2+6sZpNjzvE2KimZpHzMJHukVH0Ffkvhs0b8+S5Ut9VNUAqd3IM +JCCAEGtRNoQhM1t9Yr2zAckSvbRacp+FL/Cj9eDmyo00KsVGaeefA4Dh4OW+ZhkT +NKcldXqkSuj1sEf244JZYuqZp6/tAgMBAAECgYEAi2NSVqpZMafE5YYUTcMGe6QS +k2jtpsqYgggI2RnLJ/2tNZwYI5pwP8QVSbnMaiF4gokD5hGdrNDfTnb2v+yIwYEH +0w8+oG7Z81KodsiZSIDJfTGsAZhVNwOz9y0VD8BBZZ1/274Zh52AUKLjZS/ZwIbS +W2ywya855dPnH/wj+0ECQQD9X8D920kByTNHhBG18biAEZ4pxs9f0OAG8333eVcI +w2lJDLsYDZrCB2ocgA3lUdozlzPC7YDYw8reg0tkiRY5AkEA7sdNzOeQsQRn7++5 +0bP9DtT/iON1gbfxRzCfCfXdoOtfQWIzTePWtURt9X/5D9NofI0Rg5W2oGy/MLe5 +/sXHVQJBAIup5XrJDkQywNZyAUU2ecn2bCWBFjwtqd+LBmuMciI9fOKsZtEKZrz/ +U0lkeMRoSwvXE8wmGLjjrAbdfohrXFkCQQDZEx/LtIl6JINJQiswVe0tWr6k+ASP +1WXoTm+HYpoF/XUvv9LccNF1IazFj34hwRQwhx7w/V52Ieb+p0jUMYGxAkEAjDhd +9pBO1fKXWiXzi9ZKfoyTNcUq3eBSVKwPG2nItg5ycXengjT5sgcWDnciIzW7BIVI +JiqOszq9GWESErAatg== +-----END PRIVATE KEY----- diff --git a/src/ruby/spec/testdata/client.pem b/src/ruby/spec/testdata/client.pem new file mode 100644 index 00000000000..e332091019b --- /dev/null +++ b/src/ruby/spec/testdata/client.pem @@ -0,0 +1,14 @@ +-----BEGIN CERTIFICATE----- +MIICHzCCAYgCAQEwDQYJKoZIhvcNAQEFBQAwVjELMAkGA1UEBhMCQVUxEzARBgNV +BAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0 +ZDEPMA0GA1UEAwwGdGVzdGNhMB4XDTE0MDcxNzIzNTYwMloXDTI0MDcxNDIzNTYw +MlowWjELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDETMBEGA1UEAwwKdGVzdGNsaWVudDCB +nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA7FRH26G+Ft5VQgyzlZsfSnHSZ6GX +b7qxmk2PO8TYqKZmkfMwke6RUfQV+S+GzRvz5LlS31U1QCp3cgwkIIAQa1E2hCEz +W31ivbMByRK9tFpyn4Uv8KP14ObKjTQqxUZp558DgOHg5b5mGRM0pyV1eqRK6PWw +R/bjglli6pmnr+0CAwEAATANBgkqhkiG9w0BAQUFAAOBgQAStSm5PM7ubROiKK6/ +T2FkKlhiTOx+Ryenm3Eio59emq+jXl+1nhPySX5G2PQzSR5vd1dIhwgZSR4Gyttk +tRZ57k/NI1brUW8joiEOMJA/Mr7H7asx7wIRYDE91Fs8GkKWd5LhoPAQj+qdG35C +OO+svdkmqH0KZo320ZUqdl2ooQ== +-----END CERTIFICATE----- From ae5130da08c94cf4ca8c83c87256325233c9f024 Mon Sep 17 00:00:00 2001 From: Adele Zhou Date: Thu, 20 Jul 2017 16:31:11 -0700 Subject: [PATCH 071/127] Download the json file --- tools/internal_ci/helper_scripts/prepare_build_interop_rc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/internal_ci/helper_scripts/prepare_build_interop_rc b/tools/internal_ci/helper_scripts/prepare_build_interop_rc index cc956b80752..859ce621f97 100644 --- a/tools/internal_ci/helper_scripts/prepare_build_interop_rc +++ b/tools/internal_ci/helper_scripts/prepare_build_interop_rc @@ -26,3 +26,8 @@ git submodule update --init # Set up gRPC-Go and gRPC-Java to test git clone --recursive https://github.com/grpc/grpc-go ./../grpc-go git clone --recursive https://github.com/grpc/grpc-java ./../grpc-java + +# Download json file. +mkdir ~/service_account +gsutil cp gs://grpc-testing-secrets/interop/service_account/GrpcTesting-726eb1347f15.json ~/service_account +export GOOGLE_APPLICATION_CREDENTIALS=~/service_account/GrpcTesting-726eb1347f15.json From 9d7def71fe04ec25b7cace53adb5775dbcccc353 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 20 Jul 2017 16:41:27 -0700 Subject: [PATCH 072/127] Address comments: change names and remove unnecessary lines --- src/core/lib/iomgr/iomgr_uv.c | 4 ++-- src/core/lib/iomgr/iomgr_uv.h | 8 ++++---- src/core/lib/iomgr/pollset_uv.c | 12 ++++++------ src/core/lib/iomgr/resolve_address_uv.c | 4 ++-- src/core/lib/iomgr/tcp_client_uv.c | 2 +- src/core/lib/iomgr/tcp_server_uv.c | 14 +++++++------- src/core/lib/iomgr/tcp_uv.c | 4 ++-- src/core/lib/iomgr/timer_uv.c | 6 +++--- 8 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/core/lib/iomgr/iomgr_uv.c b/src/core/lib/iomgr/iomgr_uv.c index ffec6bcf766..df5d23af3bb 100644 --- a/src/core/lib/iomgr/iomgr_uv.c +++ b/src/core/lib/iomgr/iomgr_uv.c @@ -26,14 +26,14 @@ #include "src/core/lib/iomgr/pollset_uv.h" #include "src/core/lib/iomgr/tcp_uv.h" -gpr_thd_id grpc_init_thread; +gpr_thd_id g_init_thread; void grpc_iomgr_platform_init(void) { grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_pollset_global_init(); grpc_register_tracer(&grpc_tcp_trace); grpc_executor_set_threading(&exec_ctx, false); - grpc_init_thread = gpr_thd_currentid(); + g_init_thread = gpr_thd_currentid(); grpc_exec_ctx_finish(&exec_ctx); } void grpc_iomgr_platform_flush(void) {} diff --git a/src/core/lib/iomgr/iomgr_uv.h b/src/core/lib/iomgr/iomgr_uv.h index bd406c34f72..3b4daaa73ba 100644 --- a/src/core/lib/iomgr/iomgr_uv.h +++ b/src/core/lib/iomgr/iomgr_uv.h @@ -25,13 +25,13 @@ /* The thread ID of the thread on which grpc was initialized. Used to verify * that all calls into libuv are made on that same thread */ -extern gpr_thd_id grpc_init_thread; +extern gpr_thd_id g_init_thread; #ifdef GRPC_UV_THREAD_CHECK -#define GRPC_ASSERT_SAME_THREAD() \ - GPR_ASSERT(gpr_thd_currentid() == grpc_init_thread) +#define GRPC_UV_ASSERT_SAME_THREAD() \ + GPR_ASSERT(gpr_thd_currentid() == g_init_thread) #else -#define GRPC_ASSERT_SAME_THREAD() +#define GRPC_UV_ASSERT_SAME_THREAD() #endif /* GRPC_UV_THREAD_CHECK */ #endif /* GRPC_CORE_LIB_IOMGR_IOMGR_UV_H */ diff --git a/src/core/lib/iomgr/pollset_uv.c b/src/core/lib/iomgr/pollset_uv.c index e59801834dd..a79fe89d3ef 100644 --- a/src/core/lib/iomgr/pollset_uv.c +++ b/src/core/lib/iomgr/pollset_uv.c @@ -71,7 +71,7 @@ void grpc_pollset_global_init(void) { } void grpc_pollset_global_shutdown(void) { - GRPC_ASSERT_SAME_THREAD(); + GRPC_UV_ASSERT_SAME_THREAD(); gpr_mu_destroy(&grpc_polling_mu); uv_close((uv_handle_t *)dummy_uv_handle, dummy_handle_close_cb); } @@ -81,7 +81,7 @@ static void timer_run_cb(uv_timer_t *timer) {} static void timer_close_cb(uv_handle_t *handle) { handle->data = (void *)1; } void grpc_pollset_init(grpc_pollset *pollset, gpr_mu **mu) { - GRPC_ASSERT_SAME_THREAD(); + GRPC_UV_ASSERT_SAME_THREAD(); *mu = &grpc_polling_mu; uv_timer_init(uv_default_loop(), &pollset->timer); pollset->shutting_down = 0; @@ -90,7 +90,7 @@ void grpc_pollset_init(grpc_pollset *pollset, gpr_mu **mu) { void grpc_pollset_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_closure *closure) { GPR_ASSERT(!pollset->shutting_down); - GRPC_ASSERT_SAME_THREAD(); + GRPC_UV_ASSERT_SAME_THREAD(); pollset->shutting_down = 1; if (grpc_pollset_work_run_loop) { // Drain any pending UV callbacks without blocking @@ -103,7 +103,7 @@ void grpc_pollset_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, } void grpc_pollset_destroy(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset) { - GRPC_ASSERT_SAME_THREAD(); + GRPC_UV_ASSERT_SAME_THREAD(); uv_close((uv_handle_t *)&pollset->timer, timer_close_cb); // timer.data is a boolean indicating that the timer has finished closing pollset->timer.data = (void *)0; @@ -118,7 +118,7 @@ grpc_error *grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_pollset_worker **worker_hdl, gpr_timespec now, gpr_timespec deadline) { uint64_t timeout; - GRPC_ASSERT_SAME_THREAD(); + GRPC_UV_ASSERT_SAME_THREAD(); gpr_mu_unlock(&grpc_polling_mu); if (grpc_pollset_work_run_loop) { if (gpr_time_cmp(deadline, now) >= 0) { @@ -147,7 +147,7 @@ grpc_error *grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_error *grpc_pollset_kick(grpc_pollset *pollset, grpc_pollset_worker *specific_worker) { - GRPC_ASSERT_SAME_THREAD(); + GRPC_UV_ASSERT_SAME_THREAD(); uv_timer_start(dummy_uv_handle, dummy_timer_cb, 0, 0); return GRPC_ERROR_NONE; } diff --git a/src/core/lib/iomgr/resolve_address_uv.c b/src/core/lib/iomgr/resolve_address_uv.c index f910ec26b26..2d438e8b486 100644 --- a/src/core/lib/iomgr/resolve_address_uv.c +++ b/src/core/lib/iomgr/resolve_address_uv.c @@ -175,7 +175,7 @@ static grpc_error *blocking_resolve_address_impl( grpc_error *err; int retry_status; - GRPC_ASSERT_SAME_THREAD(); + GRPC_UV_ASSERT_SAME_THREAD(); req.addrinfo = NULL; @@ -231,7 +231,7 @@ static void resolve_address_impl(grpc_exec_ctx *exec_ctx, const char *name, char *port = NULL; grpc_error *err; int s; - GRPC_ASSERT_SAME_THREAD(); + GRPC_UV_ASSERT_SAME_THREAD(); err = try_split_host_port(name, default_port, &host, &port); if (err != GRPC_ERROR_NONE) { GRPC_CLOSURE_SCHED(exec_ctx, on_done, err); diff --git a/src/core/lib/iomgr/tcp_client_uv.c b/src/core/lib/iomgr/tcp_client_uv.c index 098ff7648de..786c456b735 100644 --- a/src/core/lib/iomgr/tcp_client_uv.c +++ b/src/core/lib/iomgr/tcp_client_uv.c @@ -125,7 +125,7 @@ static void tcp_client_connect_impl(grpc_exec_ctx *exec_ctx, (void)channel_args; (void)interested_parties; - GRPC_ASSERT_SAME_THREAD(); + GRPC_UV_ASSERT_SAME_THREAD(); if (channel_args != NULL) { for (size_t i = 0; i < channel_args->num_args; i++) { diff --git a/src/core/lib/iomgr/tcp_server_uv.c b/src/core/lib/iomgr/tcp_server_uv.c index 7b45e08c9b8..7edf22a0326 100644 --- a/src/core/lib/iomgr/tcp_server_uv.c +++ b/src/core/lib/iomgr/tcp_server_uv.c @@ -108,7 +108,7 @@ grpc_error *grpc_tcp_server_create(grpc_exec_ctx *exec_ctx, } grpc_tcp_server *grpc_tcp_server_ref(grpc_tcp_server *s) { - GRPC_ASSERT_SAME_THREAD(); + GRPC_UV_ASSERT_SAME_THREAD(); gpr_ref(&s->refs); return s; } @@ -147,12 +147,10 @@ static void handle_close_callback(uv_handle_t *handle) { } static void close_listener(grpc_tcp_listener *sp) { - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; if (!sp->closed) { sp->closed = true; uv_close((uv_handle_t *)sp->handle, handle_close_callback); } - grpc_exec_ctx_finish(&exec_ctx); } static void tcp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) { @@ -175,7 +173,7 @@ static void tcp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) { } void grpc_tcp_server_unref(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) { - GRPC_ASSERT_SAME_THREAD(); + GRPC_UV_ASSERT_SAME_THREAD(); if (gpr_unref(&s->refs)) { /* Complete shutdown_starting work before destroying. */ grpc_exec_ctx local_exec_ctx = GRPC_EXEC_CTX_INIT; @@ -248,7 +246,9 @@ static void on_connect(uv_stream_t *server, int status) { GPR_ASSERT(!sp->has_pending_connection); - gpr_log(GPR_DEBUG, "SERVER_CONNECT: %p incoming connection", sp->server); + if (GRPC_TRACER_ON(grpc_tcp_trace)) { + gpr_log(GPR_DEBUG, "SERVER_CONNECT: %p incoming connection", sp->server); + } // Create acceptor. if (sp->server->on_accept_cb) { @@ -338,7 +338,7 @@ grpc_error *grpc_tcp_server_add_port(grpc_tcp_server *s, int status; grpc_error *error = GRPC_ERROR_NONE; - GRPC_ASSERT_SAME_THREAD(); + GRPC_UV_ASSERT_SAME_THREAD(); if (s->tail != NULL) { port_index = s->tail->port_index + 1; @@ -420,7 +420,7 @@ void grpc_tcp_server_start(grpc_exec_ctx *exec_ctx, grpc_tcp_server *server, grpc_tcp_listener *sp; (void)pollsets; (void)pollset_count; - GRPC_ASSERT_SAME_THREAD(); + GRPC_UV_ASSERT_SAME_THREAD(); if (GRPC_TRACER_ON(grpc_tcp_trace)) { gpr_log(GPR_DEBUG, "SERVER_START %p", server); } diff --git a/src/core/lib/iomgr/tcp_uv.c b/src/core/lib/iomgr/tcp_uv.c index 9b1a8db7235..a05c19b4ac9 100644 --- a/src/core/lib/iomgr/tcp_uv.c +++ b/src/core/lib/iomgr/tcp_uv.c @@ -184,7 +184,7 @@ static void uv_endpoint_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, grpc_tcp *tcp = (grpc_tcp *)ep; int status; grpc_error *error = GRPC_ERROR_NONE; - GRPC_ASSERT_SAME_THREAD(); + GRPC_UV_ASSERT_SAME_THREAD(); GPR_ASSERT(tcp->read_cb == NULL); tcp->read_cb = cb; tcp->read_slices = read_slices; @@ -238,7 +238,7 @@ static void uv_endpoint_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, unsigned int i; grpc_slice *slice; uv_write_t *write_req; - GRPC_ASSERT_SAME_THREAD(); + GRPC_UV_ASSERT_SAME_THREAD(); if (GRPC_TRACER_ON(grpc_tcp_trace)) { size_t j; diff --git a/src/core/lib/iomgr/timer_uv.c b/src/core/lib/iomgr/timer_uv.c index ff2570c60d1..70f49bcbe87 100644 --- a/src/core/lib/iomgr/timer_uv.c +++ b/src/core/lib/iomgr/timer_uv.c @@ -44,7 +44,7 @@ static void stop_uv_timer(uv_timer_t *handle) { void run_expired_timer(uv_timer_t *handle) { grpc_timer *timer = (grpc_timer *)handle->data; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - GRPC_ASSERT_SAME_THREAD(); + GRPC_UV_ASSERT_SAME_THREAD(); GPR_ASSERT(timer->pending); timer->pending = 0; GRPC_CLOSURE_SCHED(&exec_ctx, timer->closure, GRPC_ERROR_NONE); @@ -57,7 +57,7 @@ void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer, gpr_timespec now) { uint64_t timeout; uv_timer_t *uv_timer; - GRPC_ASSERT_SAME_THREAD(); + GRPC_UV_ASSERT_SAME_THREAD(); timer->closure = closure; if (gpr_time_cmp(deadline, now) <= 0) { timer->pending = 0; @@ -78,7 +78,7 @@ void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer, } void grpc_timer_cancel(grpc_exec_ctx *exec_ctx, grpc_timer *timer) { - GRPC_ASSERT_SAME_THREAD(); + GRPC_UV_ASSERT_SAME_THREAD(); if (timer->pending) { timer->pending = 0; GRPC_CLOSURE_SCHED(exec_ctx, timer->closure, GRPC_ERROR_CANCELLED); From c62ce80b805837dc2246b453a4a8b76c886cb6a3 Mon Sep 17 00:00:00 2001 From: Yash Tibrewal Date: Thu, 20 Jul 2017 16:48:01 -0700 Subject: [PATCH 073/127] Test credentials are passed with channel arg. Renamed macros and refactored code as per suggestions. Renamed test to proxy_auth and changed it to use simple_request instead of a payload. --- CMakeLists.txt | 4 +- Makefile | 4 +- .../ext/filters/client_channel/http_proxy.c | 58 +- test/core/end2end/end2end_nosec_tests.c | 16 +- test/core/end2end/end2end_tests.c | 16 +- test/core/end2end/fixtures/h2_http_proxy.c | 23 +- .../end2end/fixtures/http_proxy_fixture.c | 68 +- .../end2end/fixtures/http_proxy_fixture.h | 12 +- test/core/end2end/gen_build_yaml.py | 15 +- test/core/end2end/generate_tests.bzl | 18 +- ...payload_with_proxy_auth.c => proxy_auth.c} | 155 +--- .../generated/sources_and_headers.json | 4 +- tools/run_tests/generated/tests.json | 848 +----------------- .../end2end_nosec_tests.vcxproj | 4 +- .../end2end_nosec_tests.vcxproj.filters | 6 +- .../tests/end2end_tests/end2end_tests.vcxproj | 4 +- .../end2end_tests.vcxproj.filters | 6 +- 17 files changed, 201 insertions(+), 1060 deletions(-) rename test/core/end2end/tests/{payload_with_proxy_auth.c => proxy_auth.c} (60%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1d6cf021d4d..266f2c0774a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4352,9 +4352,9 @@ add_library(end2end_tests test/core/end2end/tests/no_logging.c test/core/end2end/tests/no_op.c test/core/end2end/tests/payload.c - test/core/end2end/tests/payload_with_proxy_auth.c test/core/end2end/tests/ping.c test/core/end2end/tests/ping_pong_streaming.c + test/core/end2end/tests/proxy_auth.c test/core/end2end/tests/registered_call.c test/core/end2end/tests/request_with_flags.c test/core/end2end/tests/request_with_payload.c @@ -4452,9 +4452,9 @@ add_library(end2end_nosec_tests test/core/end2end/tests/no_logging.c test/core/end2end/tests/no_op.c test/core/end2end/tests/payload.c - test/core/end2end/tests/payload_with_proxy_auth.c test/core/end2end/tests/ping.c test/core/end2end/tests/ping_pong_streaming.c + test/core/end2end/tests/proxy_auth.c test/core/end2end/tests/registered_call.c test/core/end2end/tests/request_with_flags.c test/core/end2end/tests/request_with_payload.c diff --git a/Makefile b/Makefile index a311dee6592..7b53024b6c1 100644 --- a/Makefile +++ b/Makefile @@ -7950,9 +7950,9 @@ LIBEND2END_TESTS_SRC = \ test/core/end2end/tests/no_logging.c \ test/core/end2end/tests/no_op.c \ test/core/end2end/tests/payload.c \ - test/core/end2end/tests/payload_with_proxy_auth.c \ test/core/end2end/tests/ping.c \ test/core/end2end/tests/ping_pong_streaming.c \ + test/core/end2end/tests/proxy_auth.c \ test/core/end2end/tests/registered_call.c \ test/core/end2end/tests/request_with_flags.c \ test/core/end2end/tests/request_with_payload.c \ @@ -8045,9 +8045,9 @@ LIBEND2END_NOSEC_TESTS_SRC = \ test/core/end2end/tests/no_logging.c \ test/core/end2end/tests/no_op.c \ test/core/end2end/tests/payload.c \ - test/core/end2end/tests/payload_with_proxy_auth.c \ test/core/end2end/tests/ping.c \ test/core/end2end/tests/ping_pong_streaming.c \ + test/core/end2end/tests/proxy_auth.c \ test/core/end2end/tests/registered_call.c \ test/core/end2end/tests/request_with_flags.c \ test/core/end2end/tests/request_with_payload.c \ diff --git a/src/core/ext/filters/client_channel/http_proxy.c b/src/core/ext/filters/client_channel/http_proxy.c index 2e2471e68d6..8a14b4e57c6 100644 --- a/src/core/ext/filters/client_channel/http_proxy.c +++ b/src/core/ext/filters/client_channel/http_proxy.c @@ -30,21 +30,19 @@ #include "src/core/ext/filters/client_channel/proxy_mapper_registry.h" #include "src/core/ext/filters/client_channel/uri_parser.h" #include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/slice/b64.h" #include "src/core/lib/support/env.h" #include "src/core/lib/support/string.h" -#include "src/core/lib/slice/b64.h" /** * Parses the 'http_proxy' env var and returns the proxy hostname to resolve or - * NULL on error. Also sets 'user_cred' to user credentials present in the - * 'http_proxy' env var, NULL if not present. + * NULL on error. Also sets 'user_cred' to user credentials if present in the + * 'http_proxy' env var, otherwise leaves it unchanged. It is caller's + * responsibility to gpr_free user_cred. */ -static char *grpc_get_http_proxy_server(grpc_exec_ctx* exec_ctx, - char **user_cred) { - char *proxy_name = NULL; - if(user_cred != NULL) { - *user_cred = NULL; - } +static char* get_http_proxy_server(grpc_exec_ctx* exec_ctx, char** user_cred) { + GPR_ASSERT(user_cred != NULL); + char* proxy_name = NULL; char* uri_str = gpr_getenv("http_proxy"); if (uri_str == NULL) return NULL; grpc_uri* uri = @@ -58,27 +56,25 @@ static char *grpc_get_http_proxy_server(grpc_exec_ctx* exec_ctx, goto done; } /* Split on '@' to separate user credentials from host */ - char **authority_strs = NULL; + char** authority_strs = NULL; size_t authority_nstrs; gpr_string_split(uri->authority, "@", &authority_strs, &authority_nstrs); GPR_ASSERT(authority_nstrs != 0); /* should have at least 1 string */ - if(authority_nstrs == 1) { - /* User cred not present in authority */ - proxy_name = gpr_strdup(authority_strs[0]); - } else if(authority_nstrs == 2) { - /* User cred found */ - if(user_cred != NULL) { - *user_cred = gpr_strdup(authority_strs[0]); - } - proxy_name = gpr_strdup(authority_strs[1]); + if (authority_nstrs == 1) { + /* User cred not present in authority */ + proxy_name = authority_strs[0]; + } else if (authority_nstrs == 2) { + /* User cred found */ + *user_cred = authority_strs[0]; + proxy_name = authority_strs[1]; gpr_log(GPR_INFO, "userinfo found in proxy URI"); } else { - /* Bad authority */ + /* Bad authority */ + for (size_t i = 0; i < authority_nstrs; i++) { + gpr_free(authority_strs[i]); + } proxy_name = NULL; } - for(size_t i = 0; i < authority_nstrs; i++) { - gpr_free(authority_strs[i]); - } gpr_free(authority_strs); done: gpr_free(uri_str); @@ -92,8 +88,8 @@ static bool proxy_mapper_map_name(grpc_exec_ctx* exec_ctx, const grpc_channel_args* args, char** name_to_resolve, grpc_channel_args** new_args) { - char *user_cred = NULL; - *name_to_resolve = grpc_get_http_proxy_server(exec_ctx, &user_cred); + char* user_cred = NULL; + *name_to_resolve = get_http_proxy_server(exec_ctx, &user_cred); if (*name_to_resolve == NULL) return false; grpc_uri* uri = grpc_uri_parse(exec_ctx, server_uri, false /* suppress_errors */); @@ -163,15 +159,15 @@ static bool proxy_mapper_map_name(grpc_exec_ctx* exec_ctx, args_to_add[0] = grpc_channel_arg_string_create( GRPC_ARG_HTTP_CONNECT_SERVER, uri->path[0] == '/' ? uri->path + 1 : uri->path); - if(user_cred != NULL) { - /* Use base64 encoding for user credentials */ - char *encoded_user_cred = + if (user_cred != NULL) { + /* Use base64 encoding for user credentials as stated in RFC 7617 */ + char* encoded_user_cred = grpc_base64_encode(user_cred, strlen(user_cred), 0, 0); - char *header; + char* header; gpr_asprintf(&header, "Proxy-Authorization:Basic %s", encoded_user_cred); gpr_free(encoded_user_cred); - args_to_add[1] = grpc_channel_arg_string_create( - GRPC_ARG_HTTP_CONNECT_HEADERS, header); + args_to_add[1] = + grpc_channel_arg_string_create(GRPC_ARG_HTTP_CONNECT_HEADERS, header); *new_args = grpc_channel_args_copy_and_add(args, args_to_add, 2); gpr_free(header); } else { diff --git a/test/core/end2end/end2end_nosec_tests.c b/test/core/end2end/end2end_nosec_tests.c index 483f84e7837..6a061a4e2d7 100644 --- a/test/core/end2end/end2end_nosec_tests.c +++ b/test/core/end2end/end2end_nosec_tests.c @@ -102,12 +102,12 @@ extern void no_op(grpc_end2end_test_config config); extern void no_op_pre_init(void); extern void payload(grpc_end2end_test_config config); extern void payload_pre_init(void); -extern void payload_with_proxy_auth(grpc_end2end_test_config config); -extern void payload_with_proxy_auth_pre_init(void); extern void ping(grpc_end2end_test_config config); extern void ping_pre_init(void); extern void ping_pong_streaming(grpc_end2end_test_config config); extern void ping_pong_streaming_pre_init(void); +extern void proxy_auth(grpc_end2end_test_config config); +extern void proxy_auth_pre_init(void); extern void registered_call(grpc_end2end_test_config config); extern void registered_call_pre_init(void); extern void request_with_flags(grpc_end2end_test_config config); @@ -181,9 +181,9 @@ void grpc_end2end_tests_pre_init(void) { no_logging_pre_init(); no_op_pre_init(); payload_pre_init(); - payload_with_proxy_auth_pre_init(); ping_pre_init(); ping_pong_streaming_pre_init(); + proxy_auth_pre_init(); registered_call_pre_init(); request_with_flags_pre_init(); request_with_payload_pre_init(); @@ -245,9 +245,9 @@ void grpc_end2end_tests(int argc, char **argv, no_logging(config); no_op(config); payload(config); - payload_with_proxy_auth(config); ping(config); ping_pong_streaming(config); + proxy_auth(config); registered_call(config); request_with_flags(config); request_with_payload(config); @@ -412,10 +412,6 @@ void grpc_end2end_tests(int argc, char **argv, payload(config); continue; } - if (0 == strcmp("payload_with_proxy_auth", argv[i])) { - payload_with_proxy_auth(config); - continue; - } if (0 == strcmp("ping", argv[i])) { ping(config); continue; @@ -424,6 +420,10 @@ void grpc_end2end_tests(int argc, char **argv, ping_pong_streaming(config); continue; } + if (0 == strcmp("proxy_auth", argv[i])) { + proxy_auth(config); + continue; + } if (0 == strcmp("registered_call", argv[i])) { registered_call(config); continue; diff --git a/test/core/end2end/end2end_tests.c b/test/core/end2end/end2end_tests.c index 745546dbb7f..3fc7c3fb6cb 100644 --- a/test/core/end2end/end2end_tests.c +++ b/test/core/end2end/end2end_tests.c @@ -104,12 +104,12 @@ extern void no_op(grpc_end2end_test_config config); extern void no_op_pre_init(void); extern void payload(grpc_end2end_test_config config); extern void payload_pre_init(void); -extern void payload_with_proxy_auth(grpc_end2end_test_config config); -extern void payload_with_proxy_auth_pre_init(void); extern void ping(grpc_end2end_test_config config); extern void ping_pre_init(void); extern void ping_pong_streaming(grpc_end2end_test_config config); extern void ping_pong_streaming_pre_init(void); +extern void proxy_auth(grpc_end2end_test_config config); +extern void proxy_auth_pre_init(void); extern void registered_call(grpc_end2end_test_config config); extern void registered_call_pre_init(void); extern void request_with_flags(grpc_end2end_test_config config); @@ -184,9 +184,9 @@ void grpc_end2end_tests_pre_init(void) { no_logging_pre_init(); no_op_pre_init(); payload_pre_init(); - payload_with_proxy_auth_pre_init(); ping_pre_init(); ping_pong_streaming_pre_init(); + proxy_auth_pre_init(); registered_call_pre_init(); request_with_flags_pre_init(); request_with_payload_pre_init(); @@ -249,9 +249,9 @@ void grpc_end2end_tests(int argc, char **argv, no_logging(config); no_op(config); payload(config); - payload_with_proxy_auth(config); ping(config); ping_pong_streaming(config); + proxy_auth(config); registered_call(config); request_with_flags(config); request_with_payload(config); @@ -420,10 +420,6 @@ void grpc_end2end_tests(int argc, char **argv, payload(config); continue; } - if (0 == strcmp("payload_with_proxy_auth", argv[i])) { - payload_with_proxy_auth(config); - continue; - } if (0 == strcmp("ping", argv[i])) { ping(config); continue; @@ -432,6 +428,10 @@ void grpc_end2end_tests(int argc, char **argv, ping_pong_streaming(config); continue; } + if (0 == strcmp("proxy_auth", argv[i])) { + proxy_auth(config); + continue; + } if (0 == strcmp("registered_call", argv[i])) { registered_call(config); continue; diff --git a/test/core/end2end/fixtures/h2_http_proxy.c b/test/core/end2end/fixtures/h2_http_proxy.c index ce93c614dfa..fdc8d749c66 100644 --- a/test/core/end2end/fixtures/h2_http_proxy.c +++ b/test/core/end2end/fixtures/h2_http_proxy.c @@ -47,24 +47,13 @@ static grpc_end2end_test_fixture chttp2_create_fixture_fullstack( grpc_channel_args *client_args, grpc_channel_args *server_args) { grpc_end2end_test_fixture f; memset(&f, 0, sizeof(f)); - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - fullstack_fixture_data *ffd = gpr_malloc(sizeof(fullstack_fixture_data)); const int server_port = grpc_pick_unused_port_or_die(); gpr_join_host_port(&ffd->server_addr, "localhost", server_port); - /* If we are testing proxy auth, add the proxy auth arg to proxy channel args + /* Passing client_args to proxy_create for the case of checking for proxy auth */ - grpc_channel_args *proxy_args = NULL; - const grpc_arg *proxy_auth_arg = grpc_channel_args_find( - client_args, GRPC_END2END_HTTP_PROXY_TEST_CONNECT_AUTH_PRESENT); - if(proxy_auth_arg != NULL) { - proxy_args = grpc_channel_args_copy_and_add(NULL, proxy_auth_arg, 1); - } - ffd->proxy = grpc_end2end_http_proxy_create(proxy_args); - grpc_channel_args_destroy(&exec_ctx, proxy_args); - - grpc_exec_ctx_finish(&exec_ctx); + ffd->proxy = grpc_end2end_http_proxy_create(client_args); f.fixture_data = ffd; f.cq = grpc_completion_queue_create_for_next(NULL); @@ -79,13 +68,13 @@ void chttp2_init_client_fullstack(grpc_end2end_test_fixture *f, char *proxy_uri; /* If testing for proxy auth, add credentials to proxy uri */ - if(grpc_channel_args_find( - client_args, GRPC_END2END_HTTP_PROXY_TEST_CONNECT_AUTH_PRESENT) == NULL) { + const grpc_arg *proxy_auth = + grpc_channel_args_find(client_args, GRPC_ARG_HTTP_PROXY_AUTH_CREDS); + if (proxy_auth == NULL) { gpr_asprintf(&proxy_uri, "http://%s", grpc_end2end_http_proxy_get_proxy_name(ffd->proxy)); } else { - gpr_asprintf(&proxy_uri, "http://%s@%s", - GRPC_END2END_HTTP_PROXY_TEST_CONNECT_CRED, + gpr_asprintf(&proxy_uri, "http://%s@%s", proxy_auth->value.string, grpc_end2end_http_proxy_get_proxy_name(ffd->proxy)); } gpr_setenv("http_proxy", proxy_uri); diff --git a/test/core/end2end/fixtures/http_proxy_fixture.c b/test/core/end2end/fixtures/http_proxy_fixture.c index 239444e75fa..266351d181c 100644 --- a/test/core/end2end/fixtures/http_proxy_fixture.c +++ b/test/core/end2end/fixtures/http_proxy_fixture.c @@ -309,41 +309,23 @@ static void on_server_connect_done(grpc_exec_ctx* exec_ctx, void* arg, /** * Parses the proxy auth header value to check if it matches :- - * Basic + * Basic * Returns true if it matches, false otherwise */ -static bool proxy_auth_header_matches(grpc_exec_ctx *exec_ctx, - char *proxy_auth_header_val) { - if(proxy_auth_header_val == NULL) { +static bool proxy_auth_header_matches(grpc_exec_ctx* exec_ctx, + char* proxy_auth_header_val, + char* expected_cred) { + GPR_ASSERT(proxy_auth_header_val != NULL && expected_cred != NULL); + if (strncmp(proxy_auth_header_val, "Basic ", 6) != 0) { return false; } - char **auth_header_strs; - size_t auth_header_nstrs; - bool auth_header_matches = false; - // Split the auth header value on space - gpr_string_split(proxy_auth_header_val, " ", &auth_header_strs, - &auth_header_nstrs); - if(auth_header_nstrs != 2) { - goto done; - } - // Authentication type should be Basic - if(strcmp(auth_header_strs[0], "Basic") != 0) { - goto done; - } - // should match GRPC_END2END_HTTP_PROXY_TEST_CONNECT_CRED after decoding + proxy_auth_header_val += 6; grpc_slice decoded_slice = - grpc_base64_decode(exec_ctx, auth_header_strs[1], 0); - if(grpc_slice_str_cmp( - decoded_slice, GRPC_END2END_HTTP_PROXY_TEST_CONNECT_CRED) != 0) { - goto done; - } - auth_header_matches = true; -done: - for(size_t i = 0; i < auth_header_nstrs; i++) { - gpr_free(auth_header_strs[i]); - } - gpr_free(auth_header_strs); - return auth_header_matches; + grpc_base64_decode(exec_ctx, proxy_auth_header_val, 0); + const bool header_matches = + grpc_slice_str_cmp(decoded_slice, expected_cred) == 0; + grpc_slice_unref_internal(exec_ctx, decoded_slice); + return header_matches; } // Callback to read the HTTP CONNECT request. @@ -395,23 +377,21 @@ static void on_read_request_done(grpc_exec_ctx* exec_ctx, void* arg, return; } // If proxy auth is being used, check if the header is present and as expected - if(grpc_channel_args_find( - conn->proxy->channel_args, - GRPC_END2END_HTTP_PROXY_TEST_CONNECT_AUTH_PRESENT) != NULL) { + const grpc_arg* proxy_auth = grpc_channel_args_find( + conn->proxy->channel_args, GRPC_ARG_HTTP_PROXY_AUTH_CREDS); + if (proxy_auth != NULL) { bool auth_header_found = false; - for(size_t i = 0; i < conn->http_request.hdr_count; i++) { - if(strcmp(conn->http_request.hdrs[i].key, "Proxy-Authorization") == 0) { - if(!proxy_auth_header_matches( - exec_ctx, conn->http_request.hdrs[i].value)) { - break; - } - auth_header_found = true; + for (size_t i = 0; i < conn->http_request.hdr_count; i++) { + if (strcmp(conn->http_request.hdrs[i].key, "Proxy-Authorization") == 0) { + auth_header_found = proxy_auth_header_matches( + exec_ctx, conn->http_request.hdrs[i].value, + proxy_auth->value.string); break; } } - if(!auth_header_found) { - const char *msg = "HTTP Connect could not verify authentication"; - error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); + if (!auth_header_found) { + const char* msg = "HTTP Connect could not verify authentication"; + error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(msg); proxy_connection_failed(exec_ctx, conn, true /* is_client */, "HTTP proxy read request", error); GRPC_ERROR_UNREF(error); @@ -503,7 +483,7 @@ static void thread_main(void* arg) { } grpc_end2end_http_proxy* grpc_end2end_http_proxy_create( - grpc_channel_args *args) { + grpc_channel_args* args) { grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_end2end_http_proxy* proxy = (grpc_end2end_http_proxy*)gpr_malloc(sizeof(*proxy)); diff --git a/test/core/end2end/fixtures/http_proxy_fixture.h b/test/core/end2end/fixtures/http_proxy_fixture.h index f3da0494ae0..103bd08196c 100644 --- a/test/core/end2end/fixtures/http_proxy_fixture.h +++ b/test/core/end2end/fixtures/http_proxy_fixture.h @@ -22,20 +22,18 @@ #include /* The test credentials being used for HTTP Proxy Authorization */ -#define GRPC_END2END_HTTP_PROXY_TEST_CONNECT_CRED "aladdin:opensesame" +#define GRPC_TEST_HTTP_PROXY_AUTH_CREDS "aladdin:opensesame" /* A channel arg key used to indicate that the channel uses proxy authorization. - * The value is of no consequence as just the presence of the argument is - * enough. It is currently kept as of type integer but can be changed as seen - * fit. + * The value (string) should be the proxy auth credentials that should be + * checked. */ -#define GRPC_END2END_HTTP_PROXY_TEST_CONNECT_AUTH_PRESENT \ - "grpc.test.connect_auth" +#define GRPC_ARG_HTTP_PROXY_AUTH_CREDS "grpc.test.proxy_auth" typedef struct grpc_end2end_http_proxy grpc_end2end_http_proxy; grpc_end2end_http_proxy* grpc_end2end_http_proxy_create( - grpc_channel_args *args); + grpc_channel_args* args); void grpc_end2end_http_proxy_destroy(grpc_end2end_http_proxy* proxy); diff --git a/test/core/end2end/gen_build_yaml.py b/test/core/end2end/gen_build_yaml.py index de8508cc151..18bae63a8ac 100755 --- a/test/core/end2end/gen_build_yaml.py +++ b/test/core/end2end/gen_build_yaml.py @@ -24,9 +24,9 @@ import hashlib FixtureOptions = collections.namedtuple( 'FixtureOptions', - 'fullstack includes_proxy dns_resolver name_resolution secure platforms ci_mac tracing exclude_configs exclude_iomgrs large_writes enables_compression supports_compression is_inproc is_http2') + 'fullstack includes_proxy dns_resolver name_resolution secure platforms ci_mac tracing exclude_configs exclude_iomgrs large_writes enables_compression supports_compression is_inproc is_http2 supports_proxy_auth') default_unsecure_fixture_options = FixtureOptions( - True, False, True, True, False, ['windows', 'linux', 'mac', 'posix'], True, False, [], [], True, False, True, False, True) + True, False, True, True, False, ['windows', 'linux', 'mac', 'posix'], True, False, [], [], True, False, True, False, True, False) 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']) @@ -47,7 +47,7 @@ END2END_FIXTURES = { 'h2_full+trace': default_unsecure_fixture_options._replace(tracing=True), 'h2_full+workarounds': default_unsecure_fixture_options, 'h2_http_proxy': default_unsecure_fixture_options._replace( - ci_mac=False, exclude_iomgrs=['uv']), + ci_mac=False, exclude_iomgrs=['uv'], supports_proxy_auth=True), 'h2_oauth2': default_secure_fixture_options._replace( ci_mac=False, exclude_iomgrs=['uv']), 'h2_proxy': default_unsecure_fixture_options._replace( @@ -69,8 +69,8 @@ END2END_FIXTURES = { TestOptions = collections.namedtuple( 'TestOptions', - 'needs_fullstack needs_dns needs_names proxyable secure traceable cpu_cost exclude_iomgrs large_writes flaky allows_compression needs_compression exclude_inproc needs_http2') -default_test_options = TestOptions(False, False, False, True, False, True, 1.0, [], False, False, True, False, False, False) + 'needs_fullstack needs_dns needs_names proxyable secure traceable cpu_cost exclude_iomgrs large_writes flaky allows_compression needs_compression exclude_inproc needs_http2 needs_proxy_auth') +default_test_options = TestOptions(False, False, False, True, False, True, 1.0, [], False, False, True, False, False, False, False) connectivity_test_options = default_test_options._replace(needs_fullstack=True) LOWCPU = 0.1 @@ -125,10 +125,10 @@ END2END_TESTS = { 'no_logging': default_test_options._replace(traceable=False), 'no_op': default_test_options, 'payload': default_test_options, - 'payload_with_proxy_auth': default_test_options, 'load_reporting_hook': default_test_options, 'ping_pong_streaming': default_test_options._replace(cpu_cost=LOWCPU), 'ping': connectivity_test_options._replace(proxyable=False, cpu_cost=LOWCPU), + 'proxy_auth': default_test_options._replace(needs_proxy_auth=True), 'registered_call': default_test_options, 'request_with_flags': default_test_options._replace( proxyable=False, cpu_cost=LOWCPU), @@ -179,6 +179,9 @@ def compatible(f, t): if END2END_TESTS[t].needs_http2: if not END2END_FIXTURES[f].is_http2: return False + if END2END_TESTS[t].needs_proxy_auth: + if not END2END_FIXTURES[f].supports_proxy_auth: + return False return True diff --git a/test/core/end2end/generate_tests.bzl b/test/core/end2end/generate_tests.bzl index 1f56ddb5af3..6d1917c0ffc 100755 --- a/test/core/end2end/generate_tests.bzl +++ b/test/core/end2end/generate_tests.bzl @@ -21,7 +21,7 @@ load("//bazel:grpc_build_system.bzl", "grpc_sh_test", "grpc_cc_binary", "grpc_cc def fixture_options(fullstack=True, includes_proxy=False, dns_resolver=True, name_resolution=True, secure=True, tracing=False, platforms=['windows', 'linux', 'mac', 'posix'], - is_inproc=False, is_http2=True): + is_inproc=False, is_http2=True, supports_proxy_auth=False): return struct( fullstack=fullstack, includes_proxy=includes_proxy, @@ -30,7 +30,8 @@ def fixture_options(fullstack=True, includes_proxy=False, dns_resolver=True, secure=secure, tracing=tracing, is_inproc=is_inproc, - is_http2=is_http2 + is_http2=is_http2, + supports_proxy_auth=supports_proxy_auth #platforms=platforms ) @@ -47,7 +48,7 @@ END2END_FIXTURES = { 'h2_full+pipe': fixture_options(platforms=['linux']), 'h2_full+trace': fixture_options(tracing=True), 'h2_full+workarounds': fixture_options(), - 'h2_http_proxy': fixture_options(), + 'h2_http_proxy': fixture_options(supports_proxy_auth=True), 'h2_oauth2': fixture_options(), 'h2_proxy': fixture_options(includes_proxy=True), 'h2_sockpair_1byte': fixture_options(fullstack=False, dns_resolver=False), @@ -67,7 +68,8 @@ END2END_FIXTURES = { def test_options(needs_fullstack=False, needs_dns=False, needs_names=False, proxyable=True, secure=False, traceable=False, - exclude_inproc=False, needs_http2=False): + exclude_inproc=False, needs_http2=False, + needs_proxy_auth=False): return struct( needs_fullstack=needs_fullstack, needs_dns=needs_dns, @@ -76,7 +78,8 @@ def test_options(needs_fullstack=False, needs_dns=False, needs_names=False, secure=secure, traceable=traceable, exclude_inproc=exclude_inproc, - needs_http2=needs_http2 + needs_http2=needs_http2, + needs_proxy_auth=needs_proxy_auth ) @@ -120,10 +123,10 @@ END2END_TESTS = { 'no_logging': test_options(traceable=False), 'no_op': test_options(), 'payload': test_options(), - 'payload_with_proxy_auth': test_options(), 'load_reporting_hook': test_options(), 'ping_pong_streaming': test_options(), 'ping': test_options(needs_fullstack=True, proxyable=False), + 'proxy_auth': test_options(needs_proxy_auth=True), 'registered_call': test_options(), 'request_with_flags': test_options(proxyable=False), 'request_with_payload': test_options(), @@ -166,6 +169,9 @@ def compatible(fopt, topt): if topt.needs_http2: if not fopt.is_http2: return False + if topt.needs_proxy_auth: + if not fopt.supports_proxy_auth: + return False return True diff --git a/test/core/end2end/tests/payload_with_proxy_auth.c b/test/core/end2end/tests/proxy_auth.c similarity index 60% rename from test/core/end2end/tests/payload_with_proxy_auth.c rename to test/core/end2end/tests/proxy_auth.c index 4d176f9145b..d922049bcb5 100644 --- a/test/core/end2end/tests/payload_with_proxy_auth.c +++ b/test/core/end2end/tests/proxy_auth.c @@ -16,6 +16,10 @@ * */ +/** + * This test is for checking whether proxy authentication is working with HTTP + * Connect. + */ #include "test/core/end2end/end2end_tests.h" #include "test/core/end2end/fixtures/http_proxy_fixture.h" @@ -23,10 +27,12 @@ #include #include +#include #include #include #include #include +#include "src/core/lib/support/string.h" #include "test/core/end2end/cq_verifier.h" static void *tag(intptr_t t) { return (void *)t; } @@ -85,53 +91,24 @@ static void end_test(grpc_end2end_test_fixture *f) { grpc_completion_queue_destroy(f->shutdown_cq); } -/* Creates and returns a grpc_slice containing random alphanumeric characters. - */ -static grpc_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'; - grpc_slice out = grpc_slice_from_copied_string(output); - gpr_free(output); - return out; -} - -static void request_response_with_payload_and_proxy_auth - (grpc_end2end_test_config config, - grpc_end2end_test_fixture f) { - /* 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. */ - grpc_slice request_payload_slice = generate_random_slice(); - grpc_slice response_payload_slice = generate_random_slice(); - +static void simple_request_body(grpc_end2end_test_config config, + grpc_end2end_test_fixture f) { grpc_call *c; grpc_call *s; - grpc_byte_buffer *request_payload = - grpc_raw_byte_buffer_create(&request_payload_slice, 1); - grpc_byte_buffer *response_payload = - grpc_raw_byte_buffer_create(&response_payload_slice, 1); cq_verifier *cqv = cq_verifier_create(f.cq); grpc_op ops[6]; grpc_op *op; grpc_metadata_array initial_metadata_recv; grpc_metadata_array trailing_metadata_recv; grpc_metadata_array request_metadata_recv; - grpc_byte_buffer *request_payload_recv = NULL; - grpc_byte_buffer *response_payload_recv = NULL; grpc_call_details call_details; grpc_status_code status; grpc_call_error error; grpc_slice details; int was_cancelled = 2; + char *peer; - gpr_timespec deadline = n_seconds_from_now(60); + gpr_timespec deadline = five_seconds_from_now(); c = grpc_channel_create_call( f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, grpc_slice_from_static_string("/foo"), @@ -139,6 +116,11 @@ static void request_response_with_payload_and_proxy_auth NULL); GPR_ASSERT(c); + peer = grpc_call_get_peer(c); + GPR_ASSERT(peer != NULL); + gpr_log(GPR_DEBUG, "client_peer_before_call=%s", peer); + gpr_free(peer); + grpc_metadata_array_init(&initial_metadata_recv); grpc_metadata_array_init(&trailing_metadata_recv); grpc_metadata_array_init(&request_metadata_recv); @@ -151,11 +133,6 @@ static void request_response_with_payload_and_proxy_auth op->flags = 0; op->reserved = NULL; op++; - op->op = GRPC_OP_SEND_MESSAGE; - op->data.send_message.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; @@ -165,11 +142,6 @@ static void request_response_with_payload_and_proxy_auth op->flags = 0; op->reserved = NULL; op++; - op->op = GRPC_OP_RECV_MESSAGE; - op->data.recv_message.recv_message = &response_payload_recv; - 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; op->data.recv_status_on_client.status = &status; @@ -187,6 +159,15 @@ static void request_response_with_payload_and_proxy_auth CQ_EXPECT_COMPLETION(cqv, tag(101), 1); cq_verify(cqv); + peer = grpc_call_get_peer(s); + GPR_ASSERT(peer != NULL); + gpr_log(GPR_DEBUG, "server_peer=%s", peer); + gpr_free(peer); + peer = grpc_call_get_peer(c); + GPR_ASSERT(peer != NULL); + gpr_log(GPR_DEBUG, "client_peer=%s", peer); + gpr_free(peer); + memset(ops, 0, sizeof(ops)); op = ops; op->op = GRPC_OP_SEND_INITIAL_METADATA; @@ -194,53 +175,33 @@ static void request_response_with_payload_and_proxy_auth op->flags = 0; op->reserved = NULL; op++; - op->op = GRPC_OP_RECV_MESSAGE; - op->data.recv_message.recv_message = &request_payload_recv; + 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_UNIMPLEMENTED; + grpc_slice status_details = grpc_slice_from_static_string("xyz"); + op->data.send_status_from_server.status_details = &status_details; op->flags = 0; op->reserved = NULL; op++; - error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), NULL); - GPR_ASSERT(GRPC_CALL_OK == error); - - CQ_EXPECT_COMPLETION(cqv, tag(102), 1); - cq_verify(cqv); - - memset(ops, 0, sizeof(ops)); - op = ops; op->op = GRPC_OP_RECV_CLOSE_ON_SERVER; op->data.recv_close_on_server.cancelled = &was_cancelled; op->flags = 0; op->reserved = NULL; op++; - op->op = GRPC_OP_SEND_MESSAGE; - op->data.send_message.send_message = response_payload; - 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; - grpc_slice status_details = grpc_slice_from_static_string("xyz"); - op->data.send_status_from_server.status_details = &status_details; - op->flags = 0; - op->reserved = NULL; - op++; - error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), NULL); + error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), NULL); GPR_ASSERT(GRPC_CALL_OK == error); - CQ_EXPECT_COMPLETION(cqv, tag(103), 1); + CQ_EXPECT_COMPLETION(cqv, tag(102), 1); CQ_EXPECT_COMPLETION(cqv, tag(1), 1); cq_verify(cqv); - GPR_ASSERT(status == GRPC_STATUS_OK); + GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED); GPR_ASSERT(0 == grpc_slice_str_cmp(details, "xyz")); GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/foo")); validate_host_override_string("foo.test.google.fr:1234", call_details.host, config); - GPR_ASSERT(was_cancelled == 0); - GPR_ASSERT(byte_buffer_eq_slice(request_payload_recv, request_payload_slice)); - GPR_ASSERT( - byte_buffer_eq_slice(response_payload_recv, response_payload_slice)); + GPR_ASSERT(0 == call_details.flags); + GPR_ASSERT(was_cancelled == 1); grpc_slice_unref(details); grpc_metadata_array_destroy(&initial_metadata_recv); @@ -252,51 +213,23 @@ static void request_response_with_payload_and_proxy_auth grpc_call_unref(s); cq_verifier_destroy(cqv); - - grpc_byte_buffer_destroy(request_payload); - grpc_byte_buffer_destroy(response_payload); - grpc_byte_buffer_destroy(request_payload_recv); - grpc_byte_buffer_destroy(response_payload_recv); -} - -/* Client sends a request with payload, server reads then returns a response - payload and status. */ -static void test_invoke_request_response_with_payload_and_proxy_auth( - grpc_end2end_test_config config) { - /* Indicate that the proxy requires user auth */ - grpc_arg client_arg = {.type = GRPC_ARG_INTEGER, - .key = GRPC_END2END_HTTP_PROXY_TEST_CONNECT_AUTH_PRESENT, - .value.integer = 0}; - grpc_channel_args client_args = {.num_args = 1, .args = &client_arg}; - grpc_end2end_test_fixture f = begin_test( - config, "test_invoke_request_response_with_payload_and_proxy_auth", - &client_args, NULL); - request_response_with_payload_and_proxy_auth(config, f); - end_test(&f); - config.tear_down_data(&f); } -static void test_invoke_10_request_response_with_payload_and_proxy_auth( - grpc_end2end_test_config config) { - int i; +static void test_invoke_proxy_auth(grpc_end2end_test_config config) { /* Indicate that the proxy requires user auth */ - grpc_arg client_arg = {.type = GRPC_ARG_INTEGER, - .key = GRPC_END2END_HTTP_PROXY_TEST_CONNECT_AUTH_PRESENT, - .value.integer = 0}; + grpc_arg client_arg = {.type = GRPC_ARG_STRING, + .key = GRPC_ARG_HTTP_PROXY_AUTH_CREDS, + .value.string = GRPC_TEST_HTTP_PROXY_AUTH_CREDS}; grpc_channel_args client_args = {.num_args = 1, .args = &client_arg}; - grpc_end2end_test_fixture f = begin_test( - config, "test_invoke_10_request_response_with_payload_and_proxy_auth", - &client_args, NULL); - for (i = 0; i < 10; i++) { - request_response_with_payload_and_proxy_auth(config, f); - } + grpc_end2end_test_fixture f = + begin_test(config, "test_invoke_proxy_auth", &client_args, NULL); + simple_request_body(config, f); end_test(&f); config.tear_down_data(&f); } -void payload_with_proxy_auth(grpc_end2end_test_config config) { - test_invoke_request_response_with_payload_and_proxy_auth(config); - test_invoke_10_request_response_with_payload_and_proxy_auth(config); +void proxy_auth(grpc_end2end_test_config config) { + test_invoke_proxy_auth(config); } -void payload_with_proxy_auth_pre_init(void) {} +void proxy_auth_pre_init(void) {} diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json index 313a174b332..cbd0e1d9d70 100644 --- a/tools/run_tests/generated/sources_and_headers.json +++ b/tools/run_tests/generated/sources_and_headers.json @@ -7337,9 +7337,9 @@ "test/core/end2end/tests/no_logging.c", "test/core/end2end/tests/no_op.c", "test/core/end2end/tests/payload.c", - "test/core/end2end/tests/payload_with_proxy_auth.c", "test/core/end2end/tests/ping.c", "test/core/end2end/tests/ping_pong_streaming.c", + "test/core/end2end/tests/proxy_auth.c", "test/core/end2end/tests/registered_call.c", "test/core/end2end/tests/request_with_flags.c", "test/core/end2end/tests/request_with_payload.c", @@ -7415,9 +7415,9 @@ "test/core/end2end/tests/no_logging.c", "test/core/end2end/tests/no_op.c", "test/core/end2end/tests/payload.c", - "test/core/end2end/tests/payload_with_proxy_auth.c", "test/core/end2end/tests/ping.c", "test/core/end2end/tests/ping_pong_streaming.c", + "test/core/end2end/tests/proxy_auth.c", "test/core/end2end/tests/registered_call.c", "test/core/end2end/tests/request_with_flags.c", "test/core/end2end/tests/request_with_payload.c", diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json index 901e869e7cd..767a5ce1473 100644 --- a/tools/run_tests/generated/tests.json +++ b/tools/run_tests/generated/tests.json @@ -6629,29 +6629,6 @@ "posix" ] }, - { - "args": [ - "payload_with_proxy_auth" - ], - "ci_platforms": [ - "windows", - "linux", - "mac", - "posix" - ], - "cpu_cost": 1.0, - "exclude_configs": [], - "exclude_iomgrs": [], - "flaky": false, - "language": "c", - "name": "h2_census_test", - "platforms": [ - "windows", - "linux", - "mac", - "posix" - ] - }, { "args": [ "ping" @@ -7921,29 +7898,6 @@ "posix" ] }, - { - "args": [ - "payload_with_proxy_auth" - ], - "ci_platforms": [ - "windows", - "linux", - "mac", - "posix" - ], - "cpu_cost": 1.0, - "exclude_configs": [], - "exclude_iomgrs": [], - "flaky": false, - "language": "c", - "name": "h2_compress_test", - "platforms": [ - "windows", - "linux", - "mac", - "posix" - ] - }, { "args": [ "ping" @@ -9153,28 +9107,6 @@ "posix" ] }, - { - "args": [ - "payload_with_proxy_auth" - ], - "ci_platforms": [ - "windows", - "linux", - "posix" - ], - "cpu_cost": 1.0, - "exclude_configs": [], - "exclude_iomgrs": [], - "flaky": false, - "language": "c", - "name": "h2_fakesec_test", - "platforms": [ - "windows", - "linux", - "mac", - "posix" - ] - }, { "args": [ "ping" @@ -10307,29 +10239,6 @@ "posix" ] }, - { - "args": [ - "payload_with_proxy_auth" - ], - "ci_platforms": [ - "linux", - "mac", - "posix" - ], - "cpu_cost": 1.0, - "exclude_configs": [], - "exclude_iomgrs": [ - "uv" - ], - "flaky": false, - "language": "c", - "name": "h2_fd_test", - "platforms": [ - "linux", - "mac", - "posix" - ] - }, { "args": [ "ping_pong_streaming" @@ -11553,29 +11462,6 @@ "posix" ] }, - { - "args": [ - "payload_with_proxy_auth" - ], - "ci_platforms": [ - "windows", - "linux", - "mac", - "posix" - ], - "cpu_cost": 1.0, - "exclude_configs": [], - "exclude_iomgrs": [], - "flaky": false, - "language": "c", - "name": "h2_full_test", - "platforms": [ - "windows", - "linux", - "mac", - "posix" - ] - }, { "args": [ "ping" @@ -12693,25 +12579,6 @@ "linux" ] }, - { - "args": [ - "payload_with_proxy_auth" - ], - "ci_platforms": [ - "linux" - ], - "cpu_cost": 1.0, - "exclude_configs": [], - "exclude_iomgrs": [ - "uv" - ], - "flaky": false, - "language": "c", - "name": "h2_full+pipe_test", - "platforms": [ - "linux" - ] - }, { "args": [ "ping" @@ -13863,29 +13730,6 @@ "posix" ] }, - { - "args": [ - "payload_with_proxy_auth" - ], - "ci_platforms": [ - "windows", - "linux", - "mac", - "posix" - ], - "cpu_cost": 1.0, - "exclude_configs": [], - "exclude_iomgrs": [], - "flaky": false, - "language": "c", - "name": "h2_full+trace_test", - "platforms": [ - "windows", - "linux", - "mac", - "posix" - ] - }, { "args": [ "ping" @@ -15155,29 +14999,6 @@ "posix" ] }, - { - "args": [ - "payload_with_proxy_auth" - ], - "ci_platforms": [ - "windows", - "linux", - "mac", - "posix" - ], - "cpu_cost": 1.0, - "exclude_configs": [], - "exclude_iomgrs": [], - "flaky": false, - "language": "c", - "name": "h2_full+workarounds_test", - "platforms": [ - "windows", - "linux", - "mac", - "posix" - ] - }, { "args": [ "ping" @@ -16482,14 +16303,14 @@ }, { "args": [ - "payload_with_proxy_auth" + "ping" ], "ci_platforms": [ "windows", "linux", "posix" ], - "cpu_cost": 1.0, + "cpu_cost": 0.1, "exclude_configs": [], "exclude_iomgrs": [ "uv" @@ -16506,7 +16327,7 @@ }, { "args": [ - "ping" + "ping_pong_streaming" ], "ci_platforms": [ "windows", @@ -16530,14 +16351,14 @@ }, { "args": [ - "ping_pong_streaming" + "proxy_auth" ], "ci_platforms": [ "windows", "linux", "posix" ], - "cpu_cost": 0.1, + "cpu_cost": 1.0, "exclude_configs": [], "exclude_iomgrs": [ "uv" @@ -17791,29 +17612,6 @@ "posix" ] }, - { - "args": [ - "payload_with_proxy_auth" - ], - "ci_platforms": [ - "windows", - "linux", - "mac", - "posix" - ], - "cpu_cost": 1.0, - "exclude_configs": [], - "exclude_iomgrs": [], - "flaky": false, - "language": "c", - "name": "h2_load_reporting_test", - "platforms": [ - "windows", - "linux", - "mac", - "posix" - ] - }, { "args": [ "ping" @@ -19116,30 +18914,6 @@ "posix" ] }, - { - "args": [ - "payload_with_proxy_auth" - ], - "ci_platforms": [ - "windows", - "linux", - "posix" - ], - "cpu_cost": 1.0, - "exclude_configs": [], - "exclude_iomgrs": [ - "uv" - ], - "flaky": false, - "language": "c", - "name": "h2_oauth2_test", - "platforms": [ - "windows", - "linux", - "mac", - "posix" - ] - }, { "args": [ "ping" @@ -20294,7 +20068,31 @@ }, { "args": [ - "payload_with_proxy_auth" + "ping_pong_streaming" + ], + "ci_platforms": [ + "windows", + "linux", + "posix" + ], + "cpu_cost": 0.1, + "exclude_configs": [], + "exclude_iomgrs": [ + "uv" + ], + "flaky": false, + "language": "c", + "name": "h2_proxy_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "registered_call" ], "ci_platforms": [ "windows", @@ -20318,7 +20116,7 @@ }, { "args": [ - "ping_pong_streaming" + "request_with_payload" ], "ci_platforms": [ "windows", @@ -20342,14 +20140,14 @@ }, { "args": [ - "registered_call" + "server_finishes_request" ], "ci_platforms": [ "windows", "linux", "posix" ], - "cpu_cost": 1.0, + "cpu_cost": 0.1, "exclude_configs": [], "exclude_iomgrs": [ "uv" @@ -20366,55 +20164,7 @@ }, { "args": [ - "request_with_payload" - ], - "ci_platforms": [ - "windows", - "linux", - "posix" - ], - "cpu_cost": 0.1, - "exclude_configs": [], - "exclude_iomgrs": [ - "uv" - ], - "flaky": false, - "language": "c", - "name": "h2_proxy_test", - "platforms": [ - "windows", - "linux", - "mac", - "posix" - ] - }, - { - "args": [ - "server_finishes_request" - ], - "ci_platforms": [ - "windows", - "linux", - "posix" - ], - "cpu_cost": 0.1, - "exclude_configs": [], - "exclude_iomgrs": [ - "uv" - ], - "flaky": false, - "language": "c", - "name": "h2_proxy_test", - "platforms": [ - "windows", - "linux", - "mac", - "posix" - ] - }, - { - "args": [ - "shutdown_finishes_calls" + "shutdown_finishes_calls" ], "ci_platforms": [ "windows", @@ -21444,30 +21194,6 @@ "posix" ] }, - { - "args": [ - "payload_with_proxy_auth" - ], - "ci_platforms": [ - "windows", - "linux", - "posix" - ], - "cpu_cost": 1.0, - "exclude_configs": [], - "exclude_iomgrs": [ - "uv" - ], - "flaky": false, - "language": "c", - "name": "h2_sockpair_test", - "platforms": [ - "windows", - "linux", - "mac", - "posix" - ] - }, { "args": [ "ping_pong_streaming" @@ -22572,30 +22298,6 @@ "posix" ] }, - { - "args": [ - "payload_with_proxy_auth" - ], - "ci_platforms": [ - "windows", - "linux", - "posix" - ], - "cpu_cost": 1.0, - "exclude_configs": [], - "exclude_iomgrs": [ - "uv" - ], - "flaky": false, - "language": "c", - "name": "h2_sockpair+trace_test", - "platforms": [ - "windows", - "linux", - "mac", - "posix" - ] - }, { "args": [ "ping_pong_streaming" @@ -23788,32 +23490,6 @@ "posix" ] }, - { - "args": [ - "payload_with_proxy_auth" - ], - "ci_platforms": [ - "windows", - "linux", - "posix" - ], - "cpu_cost": 1.0, - "exclude_configs": [ - "msan" - ], - "exclude_iomgrs": [ - "uv" - ], - "flaky": false, - "language": "c", - "name": "h2_sockpair_1byte_test", - "platforms": [ - "windows", - "linux", - "mac", - "posix" - ] - }, { "args": [ "ping_pong_streaming" @@ -25059,29 +24735,6 @@ "posix" ] }, - { - "args": [ - "payload_with_proxy_auth" - ], - "ci_platforms": [ - "windows", - "linux", - "mac", - "posix" - ], - "cpu_cost": 1.0, - "exclude_configs": [], - "exclude_iomgrs": [], - "flaky": false, - "language": "c", - "name": "h2_ssl_test", - "platforms": [ - "windows", - "linux", - "mac", - "posix" - ] - }, { "args": [ "ping" @@ -26351,29 +26004,6 @@ "posix" ] }, - { - "args": [ - "payload_with_proxy_auth" - ], - "ci_platforms": [ - "windows", - "linux", - "mac", - "posix" - ], - "cpu_cost": 1.0, - "exclude_configs": [], - "exclude_iomgrs": [], - "flaky": false, - "language": "c", - "name": "h2_ssl_cert_test", - "platforms": [ - "windows", - "linux", - "mac", - "posix" - ] - }, { "args": [ "ping" @@ -27508,30 +27138,6 @@ "posix" ] }, - { - "args": [ - "payload_with_proxy_auth" - ], - "ci_platforms": [ - "windows", - "linux", - "posix" - ], - "cpu_cost": 1.0, - "exclude_configs": [], - "exclude_iomgrs": [ - "uv" - ], - "flaky": false, - "language": "c", - "name": "h2_ssl_proxy_test", - "platforms": [ - "windows", - "linux", - "mac", - "posix" - ] - }, { "args": [ "ping_pong_streaming" @@ -28720,29 +28326,6 @@ "posix" ] }, - { - "args": [ - "payload_with_proxy_auth" - ], - "ci_platforms": [ - "linux", - "mac", - "posix" - ], - "cpu_cost": 1.0, - "exclude_configs": [], - "exclude_iomgrs": [ - "uv" - ], - "flaky": false, - "language": "c", - "name": "h2_uds_test", - "platforms": [ - "linux", - "mac", - "posix" - ] - }, { "args": [ "ping" @@ -29755,29 +29338,6 @@ "posix" ] }, - { - "args": [ - "payload_with_proxy_auth" - ], - "ci_platforms": [ - "windows", - "linux", - "mac", - "posix" - ], - "cpu_cost": 1.0, - "exclude_configs": [], - "exclude_iomgrs": [], - "flaky": false, - "language": "c", - "name": "inproc_test", - "platforms": [ - "windows", - "linux", - "mac", - "posix" - ] - }, { "args": [ "ping_pong_streaming" @@ -30978,29 +30538,6 @@ "posix" ] }, - { - "args": [ - "payload_with_proxy_auth" - ], - "ci_platforms": [ - "windows", - "linux", - "mac", - "posix" - ], - "cpu_cost": 1.0, - "exclude_configs": [], - "exclude_iomgrs": [], - "flaky": false, - "language": "c", - "name": "h2_census_nosec_test", - "platforms": [ - "windows", - "linux", - "mac", - "posix" - ] - }, { "args": [ "ping" @@ -32249,7 +31786,7 @@ }, { "args": [ - "payload_with_proxy_auth" + "ping" ], "ci_platforms": [ "windows", @@ -32257,7 +31794,7 @@ "mac", "posix" ], - "cpu_cost": 1.0, + "cpu_cost": 0.1, "exclude_configs": [], "exclude_iomgrs": [], "flaky": false, @@ -32272,30 +31809,7 @@ }, { "args": [ - "ping" - ], - "ci_platforms": [ - "windows", - "linux", - "mac", - "posix" - ], - "cpu_cost": 0.1, - "exclude_configs": [], - "exclude_iomgrs": [], - "flaky": false, - "language": "c", - "name": "h2_compress_nosec_test", - "platforms": [ - "windows", - "linux", - "mac", - "posix" - ] - }, - { - "args": [ - "ping_pong_streaming" + "ping_pong_streaming" ], "ci_platforms": [ "windows", @@ -33374,29 +32888,6 @@ "posix" ] }, - { - "args": [ - "payload_with_proxy_auth" - ], - "ci_platforms": [ - "linux", - "mac", - "posix" - ], - "cpu_cost": 1.0, - "exclude_configs": [], - "exclude_iomgrs": [ - "uv" - ], - "flaky": false, - "language": "c", - "name": "h2_fd_nosec_test", - "platforms": [ - "linux", - "mac", - "posix" - ] - }, { "args": [ "ping_pong_streaming" @@ -34597,29 +34088,6 @@ "posix" ] }, - { - "args": [ - "payload_with_proxy_auth" - ], - "ci_platforms": [ - "windows", - "linux", - "mac", - "posix" - ], - "cpu_cost": 1.0, - "exclude_configs": [], - "exclude_iomgrs": [], - "flaky": false, - "language": "c", - "name": "h2_full_nosec_test", - "platforms": [ - "windows", - "linux", - "mac", - "posix" - ] - }, { "args": [ "ping" @@ -35718,25 +35186,6 @@ "linux" ] }, - { - "args": [ - "payload_with_proxy_auth" - ], - "ci_platforms": [ - "linux" - ], - "cpu_cost": 1.0, - "exclude_configs": [], - "exclude_iomgrs": [ - "uv" - ], - "flaky": false, - "language": "c", - "name": "h2_full+pipe_nosec_test", - "platforms": [ - "linux" - ] - }, { "args": [ "ping" @@ -36865,29 +36314,6 @@ "posix" ] }, - { - "args": [ - "payload_with_proxy_auth" - ], - "ci_platforms": [ - "windows", - "linux", - "mac", - "posix" - ], - "cpu_cost": 1.0, - "exclude_configs": [], - "exclude_iomgrs": [], - "flaky": false, - "language": "c", - "name": "h2_full+trace_nosec_test", - "platforms": [ - "windows", - "linux", - "mac", - "posix" - ] - }, { "args": [ "ping" @@ -38134,29 +37560,6 @@ "posix" ] }, - { - "args": [ - "payload_with_proxy_auth" - ], - "ci_platforms": [ - "windows", - "linux", - "mac", - "posix" - ], - "cpu_cost": 1.0, - "exclude_configs": [], - "exclude_iomgrs": [], - "flaky": false, - "language": "c", - "name": "h2_full+workarounds_nosec_test", - "platforms": [ - "windows", - "linux", - "mac", - "posix" - ] - }, { "args": [ "ping" @@ -39437,14 +38840,14 @@ }, { "args": [ - "payload_with_proxy_auth" + "ping" ], "ci_platforms": [ "windows", "linux", "posix" ], - "cpu_cost": 1.0, + "cpu_cost": 0.1, "exclude_configs": [], "exclude_iomgrs": [ "uv" @@ -39461,7 +38864,7 @@ }, { "args": [ - "ping" + "ping_pong_streaming" ], "ci_platforms": [ "windows", @@ -39485,14 +38888,14 @@ }, { "args": [ - "ping_pong_streaming" + "proxy_auth" ], "ci_platforms": [ "windows", "linux", "posix" ], - "cpu_cost": 0.1, + "cpu_cost": 1.0, "exclude_configs": [], "exclude_iomgrs": [ "uv" @@ -40723,29 +40126,6 @@ "posix" ] }, - { - "args": [ - "payload_with_proxy_auth" - ], - "ci_platforms": [ - "windows", - "linux", - "mac", - "posix" - ], - "cpu_cost": 1.0, - "exclude_configs": [], - "exclude_iomgrs": [], - "flaky": false, - "language": "c", - "name": "h2_load_reporting_nosec_test", - "platforms": [ - "windows", - "linux", - "mac", - "posix" - ] - }, { "args": [ "ping" @@ -41856,30 +41236,6 @@ "posix" ] }, - { - "args": [ - "payload_with_proxy_auth" - ], - "ci_platforms": [ - "windows", - "linux", - "posix" - ], - "cpu_cost": 1.0, - "exclude_configs": [], - "exclude_iomgrs": [ - "uv" - ], - "flaky": false, - "language": "c", - "name": "h2_proxy_nosec_test", - "platforms": [ - "windows", - "linux", - "mac", - "posix" - ] - }, { "args": [ "ping_pong_streaming" @@ -42984,30 +42340,6 @@ "posix" ] }, - { - "args": [ - "payload_with_proxy_auth" - ], - "ci_platforms": [ - "windows", - "linux", - "posix" - ], - "cpu_cost": 1.0, - "exclude_configs": [], - "exclude_iomgrs": [ - "uv" - ], - "flaky": false, - "language": "c", - "name": "h2_sockpair_nosec_test", - "platforms": [ - "windows", - "linux", - "mac", - "posix" - ] - }, { "args": [ "ping_pong_streaming" @@ -44088,30 +43420,6 @@ "posix" ] }, - { - "args": [ - "payload_with_proxy_auth" - ], - "ci_platforms": [ - "windows", - "linux", - "posix" - ], - "cpu_cost": 1.0, - "exclude_configs": [], - "exclude_iomgrs": [ - "uv" - ], - "flaky": false, - "language": "c", - "name": "h2_sockpair+trace_nosec_test", - "platforms": [ - "windows", - "linux", - "mac", - "posix" - ] - }, { "args": [ "ping_pong_streaming" @@ -45278,32 +44586,6 @@ "posix" ] }, - { - "args": [ - "payload_with_proxy_auth" - ], - "ci_platforms": [ - "windows", - "linux", - "posix" - ], - "cpu_cost": 1.0, - "exclude_configs": [ - "msan" - ], - "exclude_iomgrs": [ - "uv" - ], - "flaky": false, - "language": "c", - "name": "h2_sockpair_1byte_nosec_test", - "platforms": [ - "windows", - "linux", - "mac", - "posix" - ] - }, { "args": [ "ping_pong_streaming" @@ -46499,29 +45781,6 @@ "posix" ] }, - { - "args": [ - "payload_with_proxy_auth" - ], - "ci_platforms": [ - "linux", - "mac", - "posix" - ], - "cpu_cost": 1.0, - "exclude_configs": [], - "exclude_iomgrs": [ - "uv" - ], - "flaky": false, - "language": "c", - "name": "h2_uds_nosec_test", - "platforms": [ - "linux", - "mac", - "posix" - ] - }, { "args": [ "ping" @@ -47511,29 +46770,6 @@ "posix" ] }, - { - "args": [ - "payload_with_proxy_auth" - ], - "ci_platforms": [ - "windows", - "linux", - "mac", - "posix" - ], - "cpu_cost": 1.0, - "exclude_configs": [], - "exclude_iomgrs": [], - "flaky": false, - "language": "c", - "name": "inproc_nosec_test", - "platforms": [ - "windows", - "linux", - "mac", - "posix" - ] - }, { "args": [ "ping_pong_streaming" diff --git a/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj b/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj index 3a45ed619c0..249d99b526b 100644 --- a/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj +++ b/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj @@ -227,12 +227,12 @@ - - + + diff --git a/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj.filters b/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj.filters index 69bcf02b43d..3a2105ebe83 100644 --- a/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj.filters +++ b/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj.filters @@ -115,15 +115,15 @@ test\core\end2end\tests - - test\core\end2end\tests - test\core\end2end\tests test\core\end2end\tests + + test\core\end2end\tests + test\core\end2end\tests diff --git a/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj b/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj index fe1f6279805..b7a2ecd27b7 100644 --- a/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj +++ b/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj @@ -229,12 +229,12 @@ - - + + diff --git a/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj.filters b/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj.filters index 255a76e107e..1626b77d147 100644 --- a/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj.filters +++ b/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj.filters @@ -118,15 +118,15 @@ test\core\end2end\tests - - test\core\end2end\tests - test\core\end2end\tests test\core\end2end\tests + + test\core\end2end\tests + test\core\end2end\tests From 949d075812cb617eaf4d66a880869cb400f4440b Mon Sep 17 00:00:00 2001 From: Sree Kuchibhotla Date: Thu, 20 Jul 2017 23:49:15 -0700 Subject: [PATCH 074/127] Correctly fix the case where pollset->kicked_without_poller was missed --- src/core/lib/iomgr/ev_epoll1_linux.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/core/lib/iomgr/ev_epoll1_linux.c b/src/core/lib/iomgr/ev_epoll1_linux.c index 77d59059d43..b89b8af15a9 100644 --- a/src/core/lib/iomgr/ev_epoll1_linux.c +++ b/src/core/lib/iomgr/ev_epoll1_linux.c @@ -603,7 +603,7 @@ static bool begin_worker(grpc_pollset *pollset, grpc_pollset_worker *worker, worker_insert(pollset, worker); pollset->begin_refs--; - if (worker->kick_state == UNKICKED) { + if (worker->kick_state == UNKICKED && !pollset->kicked_without_poller) { GPR_ASSERT(gpr_atm_no_barrier_load(&g_active_poller) != (gpr_atm)worker); worker->initialized_cv = true; gpr_cv_init(&worker->cv); @@ -623,10 +623,13 @@ static bool begin_worker(grpc_pollset *pollset, grpc_pollset_worker *worker, } *now = gpr_now(now->clock_type); } + if (GRPC_TRACER_ON(grpc_polling_trace)) { - gpr_log(GPR_ERROR, "PS:%p BEGIN_DONE:%p kick_state=%s shutdown=%d", pollset, - worker, kick_state_string(worker->kick_state), - pollset->shutting_down); + gpr_log(GPR_ERROR, + "PS:%p BEGIN_DONE:%p kick_state=%s shutdown=%d " + "kicked_without_poller: %d", + pollset, worker, kick_state_string(worker->kick_state), + pollset->shutting_down, pollset->kicked_without_poller); } /* We release pollset lock in this function at a couple of places: From 9d87421328490e01962397bf718ab210384705e6 Mon Sep 17 00:00:00 2001 From: Sree Kuchibhotla Date: Fri, 21 Jul 2017 09:08:27 -0700 Subject: [PATCH 075/127] Disable epoll1 - so that I can merge whatever I have until now --- tools/run_tests/run_tests.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py index ddfc1d68f19..611868ce5a4 100755 --- a/tools/run_tests/run_tests.py +++ b/tools/run_tests/run_tests.py @@ -63,8 +63,8 @@ _FORCE_ENVIRON_FOR_WRAPPERS = { } _POLLING_STRATEGIES = { - 'linux': ['epoll1', 'epollsig', 'poll', 'poll-cv'], -# TODO(ctiller, sreecha): enable epollex, epoll-thread-pool + 'linux': ['epollsig', 'poll', 'poll-cv'], +# TODO(ctiller, sreecha): enable epoll1, epollex, epoll-thread-pool 'mac': ['poll'], } From c50cf03f32b7dbf006561bcbb49da8e3a65597a0 Mon Sep 17 00:00:00 2001 From: Vijay Pai Date: Fri, 21 Jul 2017 11:14:40 -0700 Subject: [PATCH 076/127] Move gtest last --- test/cpp/server/server_request_call_test.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/cpp/server/server_request_call_test.cc b/test/cpp/server/server_request_call_test.cc index 1c64ddfc67c..b0a2fa444c1 100644 --- a/test/cpp/server/server_request_call_test.cc +++ b/test/cpp/server/server_request_call_test.cc @@ -19,7 +19,6 @@ #include #include -#include #include #include @@ -32,6 +31,8 @@ #include "src/proto/grpc/testing/echo.grpc.pb.h" #include "test/core/util/port.h" +#include + namespace grpc { namespace { From 2aab728245f118b18a8ddcff102151fcc66d6960 Mon Sep 17 00:00:00 2001 From: ncteisen Date: Fri, 21 Jul 2017 11:25:56 -0700 Subject: [PATCH 077/127] regex to diff --- tools/profiling/microbenchmarks/bm_diff/bm_diff.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tools/profiling/microbenchmarks/bm_diff/bm_diff.py b/tools/profiling/microbenchmarks/bm_diff/bm_diff.py index 1ac951f3d86..a41d0f0552f 100755 --- a/tools/profiling/microbenchmarks/bm_diff/bm_diff.py +++ b/tools/profiling/microbenchmarks/bm_diff/bm_diff.py @@ -67,6 +67,12 @@ def _args(): default=20, help='Number of times to loops the benchmarks. Must match what was passed to bm_run.py' ) + argp.add_argument( + '-r', + '--regex', + type=str, + default="", + help='Regex to filter benchmarks run') argp.add_argument('--counters', dest='counters', action='store_true') argp.add_argument('--no-counters', dest='counters', action='store_false') argp.set_defaults(counters=True) @@ -212,6 +218,6 @@ def diff(bms, loops, regex, track, old, new, counters): if __name__ == '__main__': args = _args() - diff, note = diff(args.benchmarks, args.loops, args.track, args.old, + diff, note = diff(args.benchmarks, args.loops, args.regex, args.track, args.old, args.new, args.counters) print('%s\n%s' % (note, diff if diff else "No performance differences")) From d0c1e50ea91b9c4aefc7357a21daeae689d7bb48 Mon Sep 17 00:00:00 2001 From: Yash Tibrewal Date: Fri, 21 Jul 2017 12:34:38 -0700 Subject: [PATCH 078/127] Changing a few variable names and adding few safety conditions --- src/core/ext/filters/client_channel/http_proxy.c | 2 +- test/core/end2end/fixtures/h2_http_proxy.c | 6 +++--- test/core/end2end/fixtures/http_proxy_fixture.c | 15 ++++++++------- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/core/ext/filters/client_channel/http_proxy.c b/src/core/ext/filters/client_channel/http_proxy.c index 8a14b4e57c6..ef3512ed833 100644 --- a/src/core/ext/filters/client_channel/http_proxy.c +++ b/src/core/ext/filters/client_channel/http_proxy.c @@ -67,7 +67,7 @@ static char* get_http_proxy_server(grpc_exec_ctx* exec_ctx, char** user_cred) { /* User cred found */ *user_cred = authority_strs[0]; proxy_name = authority_strs[1]; - gpr_log(GPR_INFO, "userinfo found in proxy URI"); + gpr_log(GPR_DEBUG, "userinfo found in proxy URI"); } else { /* Bad authority */ for (size_t i = 0; i < authority_nstrs; i++) { diff --git a/test/core/end2end/fixtures/h2_http_proxy.c b/test/core/end2end/fixtures/h2_http_proxy.c index fdc8d749c66..61458923652 100644 --- a/test/core/end2end/fixtures/h2_http_proxy.c +++ b/test/core/end2end/fixtures/h2_http_proxy.c @@ -68,13 +68,13 @@ void chttp2_init_client_fullstack(grpc_end2end_test_fixture *f, char *proxy_uri; /* If testing for proxy auth, add credentials to proxy uri */ - const grpc_arg *proxy_auth = + const grpc_arg *proxy_auth_arg = grpc_channel_args_find(client_args, GRPC_ARG_HTTP_PROXY_AUTH_CREDS); - if (proxy_auth == NULL) { + if (proxy_auth_arg == NULL || proxy_auth_arg->type != GRPC_ARG_STRING) { gpr_asprintf(&proxy_uri, "http://%s", grpc_end2end_http_proxy_get_proxy_name(ffd->proxy)); } else { - gpr_asprintf(&proxy_uri, "http://%s@%s", proxy_auth->value.string, + gpr_asprintf(&proxy_uri, "http://%s@%s", proxy_auth_arg->value.string, grpc_end2end_http_proxy_get_proxy_name(ffd->proxy)); } gpr_setenv("http_proxy", proxy_uri); diff --git a/test/core/end2end/fixtures/http_proxy_fixture.c b/test/core/end2end/fixtures/http_proxy_fixture.c index 266351d181c..a4cfc77bcb7 100644 --- a/test/core/end2end/fixtures/http_proxy_fixture.c +++ b/test/core/end2end/fixtures/http_proxy_fixture.c @@ -315,7 +315,8 @@ static void on_server_connect_done(grpc_exec_ctx* exec_ctx, void* arg, static bool proxy_auth_header_matches(grpc_exec_ctx* exec_ctx, char* proxy_auth_header_val, char* expected_cred) { - GPR_ASSERT(proxy_auth_header_val != NULL && expected_cred != NULL); + GPR_ASSERT(proxy_auth_header_val != NULL); + GPR_ASSERT(expected_cred != NULL); if (strncmp(proxy_auth_header_val, "Basic ", 6) != 0) { return false; } @@ -377,19 +378,19 @@ static void on_read_request_done(grpc_exec_ctx* exec_ctx, void* arg, return; } // If proxy auth is being used, check if the header is present and as expected - const grpc_arg* proxy_auth = grpc_channel_args_find( + const grpc_arg* proxy_auth_arg = grpc_channel_args_find( conn->proxy->channel_args, GRPC_ARG_HTTP_PROXY_AUTH_CREDS); - if (proxy_auth != NULL) { - bool auth_header_found = false; + if (proxy_auth_arg != NULL && proxy_auth_arg->type == GRPC_ARG_STRING) { + bool client_authenticated = false; for (size_t i = 0; i < conn->http_request.hdr_count; i++) { if (strcmp(conn->http_request.hdrs[i].key, "Proxy-Authorization") == 0) { - auth_header_found = proxy_auth_header_matches( + client_authenticated = proxy_auth_header_matches( exec_ctx, conn->http_request.hdrs[i].value, - proxy_auth->value.string); + proxy_auth_arg->value.string); break; } } - if (!auth_header_found) { + if (!client_authenticated) { const char* msg = "HTTP Connect could not verify authentication"; error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(msg); proxy_connection_failed(exec_ctx, conn, true /* is_client */, From 9469ac4a7a355aede1b386d52eeb937de8a6e456 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Fri, 21 Jul 2017 12:50:35 -0700 Subject: [PATCH 079/127] transport - Move slice buffer creation to stream compression enabling time (PR 3) for performance --- .../chttp2/transport/chttp2_transport.c | 26 +++++++++++-------- .../ext/transport/chttp2/transport/internal.h | 4 +-- .../ext/transport/chttp2/transport/writing.c | 21 ++++++++------- 3 files changed, 28 insertions(+), 23 deletions(-) diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c index 41516ed91a6..212704a1219 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c @@ -668,8 +668,6 @@ static int init_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt, grpc_chttp2_incoming_metadata_buffer_init(&s->metadata_buffer[1], arena); grpc_chttp2_data_parser_init(&s->data_parser); grpc_slice_buffer_init(&s->flow_controlled_buffer); - grpc_slice_buffer_init(&s->compressed_data_buffer); - grpc_slice_buffer_init(&s->decompressed_data_buffer); s->deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC); GRPC_CLOSURE_INIT(&s->complete_fetch_locked, complete_fetch_locked, s, grpc_schedule_on_exec_ctx); @@ -708,8 +706,14 @@ static void destroy_stream_locked(grpc_exec_ctx *exec_ctx, void *sp, grpc_slice_buffer_destroy_internal(exec_ctx, &s->unprocessed_incoming_frames_buffer); grpc_slice_buffer_destroy_internal(exec_ctx, &s->frame_storage); - grpc_slice_buffer_destroy_internal(exec_ctx, &s->compressed_data_buffer); - grpc_slice_buffer_destroy_internal(exec_ctx, &s->decompressed_data_buffer); + if (s->compressed_data_buffer) { + grpc_slice_buffer_destroy_internal(exec_ctx, s->compressed_data_buffer); + gpr_free(s->compressed_data_buffer); + } + if (s->decompressed_data_buffer) { + grpc_slice_buffer_destroy_internal(exec_ctx, s->decompressed_data_buffer); + gpr_free(s->decompressed_data_buffer); + } grpc_chttp2_list_remove_stalled_by_transport(t, s); grpc_chttp2_list_remove_stalled_by_stream(t, s); @@ -1671,7 +1675,7 @@ void grpc_chttp2_maybe_complete_recv_message(grpc_exec_ctx *exec_ctx, } if (s->stream_compression_recv_enabled && !s->unprocessed_incoming_frames_decompressed) { - GPR_ASSERT(s->decompressed_data_buffer.length == 0); + GPR_ASSERT(s->decompressed_data_buffer->length == 0); bool end_of_context; if (!s->stream_decompression_ctx) { s->stream_decompression_ctx = @@ -1680,7 +1684,7 @@ void grpc_chttp2_maybe_complete_recv_message(grpc_exec_ctx *exec_ctx, } if (!grpc_stream_decompress(s->stream_decompression_ctx, &s->unprocessed_incoming_frames_buffer, - &s->decompressed_data_buffer, NULL, + s->decompressed_data_buffer, NULL, GRPC_HEADER_SIZE_IN_BYTES, &end_of_context)) { grpc_slice_buffer_reset_and_unref_internal(exec_ctx, @@ -1691,8 +1695,8 @@ void grpc_chttp2_maybe_complete_recv_message(grpc_exec_ctx *exec_ctx, "Stream decompression error."); } else { error = grpc_deframe_unprocessed_incoming_frames( - exec_ctx, &s->data_parser, s, &s->decompressed_data_buffer, - NULL, s->recv_message); + exec_ctx, &s->data_parser, s, s->decompressed_data_buffer, NULL, + s->recv_message); if (end_of_context) { grpc_stream_compression_context_destroy( s->stream_decompression_ctx); @@ -2713,15 +2717,15 @@ static grpc_error *incoming_byte_stream_pull(grpc_exec_ctx *exec_ctx, } if (!grpc_stream_decompress(s->stream_decompression_ctx, &s->unprocessed_incoming_frames_buffer, - &s->decompressed_data_buffer, NULL, - MAX_SIZE_T, &end_of_context)) { + s->decompressed_data_buffer, NULL, MAX_SIZE_T, + &end_of_context)) { error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Stream decompression error."); return error; } GPR_ASSERT(s->unprocessed_incoming_frames_buffer.length == 0); grpc_slice_buffer_swap(&s->unprocessed_incoming_frames_buffer, - &s->decompressed_data_buffer); + s->decompressed_data_buffer); s->unprocessed_incoming_frames_decompressed = true; if (end_of_context) { grpc_stream_compression_context_destroy(s->stream_decompression_ctx); diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h index 9fad6835167..eb1acc0f132 100644 --- a/src/core/ext/transport/chttp2/transport/internal.h +++ b/src/core/ext/transport/chttp2/transport/internal.h @@ -533,12 +533,12 @@ struct grpc_chttp2_stream { grpc_stream_compression_context *stream_compression_ctx; /** Buffer storing data that is compressed but not sent */ - grpc_slice_buffer compressed_data_buffer; + grpc_slice_buffer *compressed_data_buffer; /** Amount of uncompressed bytes sent out when compressed_data_buffer is * emptied */ size_t uncompressed_data_size; /** Temporary buffer storing decompressed data */ - grpc_slice_buffer decompressed_data_buffer; + grpc_slice_buffer *decompressed_data_buffer; }; /** Transport writing call flow: diff --git a/src/core/ext/transport/chttp2/transport/writing.c b/src/core/ext/transport/chttp2/transport/writing.c index 08babb73692..2e3e9ee28bf 100644 --- a/src/core/ext/transport/chttp2/transport/writing.c +++ b/src/core/ext/transport/chttp2/transport/writing.c @@ -304,7 +304,8 @@ grpc_chttp2_begin_write_result grpc_chttp2_begin_write( if (sent_initial_metadata) { /* send any body bytes, if allowed by flow control */ if (s->flow_controlled_buffer.length > 0 || - s->compressed_data_buffer.length > 0) { + (s->stream_compression_send_enabled && + s->compressed_data_buffer->length > 0)) { uint32_t stream_outgoing_window = (uint32_t)GPR_MAX( 0, s->outgoing_window_delta + @@ -319,19 +320,19 @@ grpc_chttp2_begin_write_result grpc_chttp2_begin_write( bool is_last_frame = false; if (s->stream_compression_send_enabled) { while ((s->flow_controlled_buffer.length > 0 || - s->compressed_data_buffer.length > 0) && + s->compressed_data_buffer->length > 0) && max_outgoing > 0) { - if (s->compressed_data_buffer.length > 0) { + if (s->compressed_data_buffer->length > 0) { uint32_t send_bytes = (uint32_t)GPR_MIN( - max_outgoing, s->compressed_data_buffer.length); + max_outgoing, s->compressed_data_buffer->length); is_last_data_frame = - (send_bytes == s->compressed_data_buffer.length && + (send_bytes == s->compressed_data_buffer->length && s->flow_controlled_buffer.length == 0 && s->fetching_send_message == NULL); is_last_frame = is_last_data_frame && s->send_trailing_metadata != NULL && grpc_metadata_batch_is_empty(s->send_trailing_metadata); - grpc_chttp2_encode_data(s->id, &s->compressed_data_buffer, + grpc_chttp2_encode_data(s->id, s->compressed_data_buffer, send_bytes, is_last_frame, &s->stats.outgoing, &t->outbuf); GRPC_CHTTP2_FLOW_DEBIT_STREAM( @@ -339,7 +340,7 @@ grpc_chttp2_begin_write_result grpc_chttp2_begin_write( GRPC_CHTTP2_FLOW_DEBIT_TRANSPORT("write", t, outgoing_window, send_bytes); max_outgoing -= send_bytes; - if (s->compressed_data_buffer.length == 0) { + if (s->compressed_data_buffer->length == 0) { s->sending_bytes += s->uncompressed_data_size; } } else { @@ -351,7 +352,7 @@ grpc_chttp2_begin_write_result grpc_chttp2_begin_write( s->uncompressed_data_size = s->flow_controlled_buffer.length; GPR_ASSERT(grpc_stream_compress( s->stream_compression_ctx, &s->flow_controlled_buffer, - &s->compressed_data_buffer, NULL, MAX_SIZE_T, + s->compressed_data_buffer, NULL, MAX_SIZE_T, GRPC_STREAM_COMPRESSION_FLUSH_SYNC)); } } @@ -390,7 +391,7 @@ grpc_chttp2_begin_write_result grpc_chttp2_begin_write( } now_writing = true; if (s->flow_controlled_buffer.length > 0 || - s->compressed_data_buffer.length > 0) { + s->compressed_data_buffer->length > 0) { GRPC_CHTTP2_STREAM_REF(s, "chttp2_writing:fork"); grpc_chttp2_list_add_writable_stream(t, s); } @@ -405,7 +406,7 @@ grpc_chttp2_begin_write_result grpc_chttp2_begin_write( if (s->send_trailing_metadata != NULL && s->fetching_send_message == NULL && s->flow_controlled_buffer.length == 0 && - s->compressed_data_buffer.length == 0) { + s->compressed_data_buffer->length == 0) { GRPC_CHTTP2_IF_TRACING(gpr_log(GPR_INFO, "sending trailing_metadata")); if (grpc_metadata_batch_is_empty(s->send_trailing_metadata)) { grpc_chttp2_encode_data(s->id, &s->flow_controlled_buffer, 0, true, From c7a94c5052a2409ac68b991ae116d5f9e60eb545 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Fri, 21 Jul 2017 14:04:26 -0700 Subject: [PATCH 080/127] Bug fix --- src/core/ext/transport/chttp2/transport/writing.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/core/ext/transport/chttp2/transport/writing.c b/src/core/ext/transport/chttp2/transport/writing.c index 2e3e9ee28bf..c3ede08343a 100644 --- a/src/core/ext/transport/chttp2/transport/writing.c +++ b/src/core/ext/transport/chttp2/transport/writing.c @@ -391,7 +391,8 @@ grpc_chttp2_begin_write_result grpc_chttp2_begin_write( } now_writing = true; if (s->flow_controlled_buffer.length > 0 || - s->compressed_data_buffer->length > 0) { + (s->stream_compression_send_enabled && + s->compressed_data_buffer->length > 0)) { GRPC_CHTTP2_STREAM_REF(s, "chttp2_writing:fork"); grpc_chttp2_list_add_writable_stream(t, s); } @@ -406,7 +407,8 @@ grpc_chttp2_begin_write_result grpc_chttp2_begin_write( if (s->send_trailing_metadata != NULL && s->fetching_send_message == NULL && s->flow_controlled_buffer.length == 0 && - s->compressed_data_buffer->length == 0) { + (!s->stream_compression_send_enabled || + s->compressed_data_buffer->length == 0)) { GRPC_CHTTP2_IF_TRACING(gpr_log(GPR_INFO, "sending trailing_metadata")); if (grpc_metadata_batch_is_empty(s->send_trailing_metadata)) { grpc_chttp2_encode_data(s->id, &s->flow_controlled_buffer, 0, true, From e0778b2c1817f3b7aff5af4b1b15493d4a8a207d Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Fri, 21 Jul 2017 15:42:00 -0700 Subject: [PATCH 081/127] Add cancellation to asynchronous security APIs. --- include/grpc/impl/codegen/atm.h | 1 + .../composite/composite_credentials.c | 122 ++-- .../lib/security/credentials/credentials.c | 26 +- .../lib/security/credentials/credentials.h | 74 +-- .../credentials/credentials_metadata.c | 77 +-- .../credentials/fake/fake_credentials.c | 47 +- .../credentials/fake/fake_credentials.h | 4 +- .../credentials/iam/iam_credentials.c | 45 +- .../credentials/iam/iam_credentials.h | 2 +- .../credentials/jwt/jwt_credentials.c | 51 +- .../credentials/jwt/jwt_credentials.h | 2 +- .../credentials/oauth2/oauth2_credentials.c | 193 +++++-- .../credentials/oauth2/oauth2_credentials.h | 15 +- .../credentials/plugin/plugin_credentials.c | 165 ++++-- .../credentials/plugin/plugin_credentials.h | 16 +- .../security/transport/client_auth_filter.c | 186 ++++-- .../security/transport/security_connector.c | 57 +- .../security/transport/security_connector.h | 29 +- src/node/test/credentials_test.js | 8 +- test/core/end2end/fixtures/h2_oauth2.c | 12 +- test/core/security/credentials_test.c | 530 ++++++++---------- test/core/security/oauth2_utils.c | 43 +- .../print_google_default_creds_token.c | 42 +- test/cpp/end2end/end2end_test.cc | 8 +- 24 files changed, 1006 insertions(+), 749 deletions(-) diff --git a/include/grpc/impl/codegen/atm.h b/include/grpc/impl/codegen/atm.h index c3b528be4d4..2cfd22ab637 100644 --- a/include/grpc/impl/codegen/atm.h +++ b/include/grpc/impl/codegen/atm.h @@ -60,6 +60,7 @@ int gpr_atm_no_barrier_cas(gpr_atm *p, gpr_atm o, gpr_atm n); int gpr_atm_acq_cas(gpr_atm *p, gpr_atm o, gpr_atm n); int gpr_atm_rel_cas(gpr_atm *p, gpr_atm o, gpr_atm n); + int gpr_atm_full_cas(gpr_atm *p, gpr_atm o, gpr_atm n); // Atomically, set *p=n and return the old value of *p gpr_atm gpr_atm_full_xchg(gpr_atm *p, gpr_atm n); diff --git a/src/core/lib/security/credentials/composite/composite_credentials.c b/src/core/lib/security/credentials/composite/composite_credentials.c index 77d7b04627b..09fd60a12c2 100644 --- a/src/core/lib/security/credentials/composite/composite_credentials.c +++ b/src/core/lib/security/credentials/composite/composite_credentials.c @@ -32,88 +32,98 @@ typedef struct { grpc_composite_call_credentials *composite_creds; size_t creds_index; - grpc_credentials_md_store *md_elems; - grpc_auth_metadata_context auth_md_context; - void *user_data; grpc_polling_entity *pollent; - grpc_credentials_metadata_cb cb; + grpc_auth_metadata_context auth_md_context; + grpc_credentials_mdelem_array *md_array; + grpc_closure *on_request_metadata; + grpc_closure internal_on_request_metadata; } grpc_composite_call_credentials_metadata_context; static void composite_call_destruct(grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds) { grpc_composite_call_credentials *c = (grpc_composite_call_credentials *)creds; - size_t i; - for (i = 0; i < c->inner.num_creds; i++) { + for (size_t i = 0; i < c->inner.num_creds; i++) { grpc_call_credentials_unref(exec_ctx, c->inner.creds_array[i]); } gpr_free(c->inner.creds_array); } -static void composite_call_md_context_destroy( - grpc_exec_ctx *exec_ctx, - grpc_composite_call_credentials_metadata_context *ctx) { - grpc_credentials_md_store_unref(exec_ctx, ctx->md_elems); - gpr_free(ctx); -} - -static void composite_call_metadata_cb(grpc_exec_ctx *exec_ctx, void *user_data, - grpc_credentials_md *md_elems, - size_t num_md, - grpc_credentials_status status, - const char *error_details) { +static void composite_call_metadata_cb(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { grpc_composite_call_credentials_metadata_context *ctx = - (grpc_composite_call_credentials_metadata_context *)user_data; - if (status != GRPC_CREDENTIALS_OK) { - ctx->cb(exec_ctx, ctx->user_data, NULL, 0, status, error_details); - return; - } - - /* Copy the metadata in the context. */ - if (num_md > 0) { - size_t i; - for (i = 0; i < num_md; i++) { - grpc_credentials_md_store_add(ctx->md_elems, md_elems[i].key, - md_elems[i].value); + (grpc_composite_call_credentials_metadata_context *)arg; + if (error == GRPC_ERROR_NONE) { + /* See if we need to get some more metadata. */ + if (ctx->creds_index < ctx->composite_creds->inner.num_creds) { + grpc_call_credentials *inner_creds = + ctx->composite_creds->inner.creds_array[ctx->creds_index++]; + if (grpc_call_credentials_get_request_metadata( + exec_ctx, inner_creds, ctx->pollent, ctx->auth_md_context, + ctx->md_array, &ctx->internal_on_request_metadata, &error)) { + // Synchronous response, so call ourselves recursively. + composite_call_metadata_cb(exec_ctx, arg, error); + GRPC_ERROR_UNREF(error); + } + return; } + // We're done! } - - /* See if we need to get some more metadata. */ - if (ctx->creds_index < ctx->composite_creds->inner.num_creds) { - grpc_call_credentials *inner_creds = - ctx->composite_creds->inner.creds_array[ctx->creds_index++]; - grpc_call_credentials_get_request_metadata( - exec_ctx, inner_creds, ctx->pollent, ctx->auth_md_context, - composite_call_metadata_cb, ctx); - return; - } - - /* We're done!. */ - ctx->cb(exec_ctx, ctx->user_data, ctx->md_elems->entries, - ctx->md_elems->num_entries, GRPC_CREDENTIALS_OK, NULL); - composite_call_md_context_destroy(exec_ctx, ctx); + GRPC_CLOSURE_SCHED(exec_ctx, ctx->on_request_metadata, GRPC_ERROR_REF(error)); + gpr_free(ctx); } -static void composite_call_get_request_metadata( +static bool composite_call_get_request_metadata( grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, grpc_polling_entity *pollent, grpc_auth_metadata_context auth_md_context, - grpc_credentials_metadata_cb cb, void *user_data) { + grpc_credentials_mdelem_array *md_array, grpc_closure *on_request_metadata, + grpc_error **error) { grpc_composite_call_credentials *c = (grpc_composite_call_credentials *)creds; grpc_composite_call_credentials_metadata_context *ctx; - ctx = gpr_zalloc(sizeof(grpc_composite_call_credentials_metadata_context)); - ctx->auth_md_context = auth_md_context; - ctx->user_data = user_data; - ctx->cb = cb; ctx->composite_creds = c; ctx->pollent = pollent; - ctx->md_elems = grpc_credentials_md_store_create(c->inner.num_creds); - grpc_call_credentials_get_request_metadata( - exec_ctx, c->inner.creds_array[ctx->creds_index++], ctx->pollent, - auth_md_context, composite_call_metadata_cb, ctx); + ctx->auth_md_context = auth_md_context; + ctx->md_array = md_array; + ctx->on_request_metadata = on_request_metadata; + GRPC_CLOSURE_INIT(&ctx->internal_on_request_metadata, + composite_call_metadata_cb, ctx, grpc_schedule_on_exec_ctx); + while (ctx->creds_index < ctx->composite_creds->inner.num_creds) { + grpc_call_credentials *inner_creds = + ctx->composite_creds->inner.creds_array[ctx->creds_index++]; + if (grpc_call_credentials_get_request_metadata( + exec_ctx, inner_creds, ctx->pollent, ctx->auth_md_context, + ctx->md_array, &ctx->internal_on_request_metadata, error)) { + if (*error != GRPC_ERROR_NONE) break; + } else { + break; + } + } + // If we got through all creds synchronously or we got a synchronous + // error on one of them, return synchronously. + if (ctx->creds_index == ctx->composite_creds->inner.num_creds || + *error != GRPC_ERROR_NONE) { + gpr_free(ctx); + return true; + } + // At least one inner cred is returning asynchronously, so we'll + // return asynchronously as well. + return false; +} + +static void composite_call_cancel_get_request_metadata( + grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, + grpc_credentials_mdelem_array *md_array, grpc_error *error) { + grpc_composite_call_credentials *c = (grpc_composite_call_credentials *)creds; + for (size_t i = 0; i < c->inner.num_creds; ++i) { + grpc_call_credentials_cancel_get_request_metadata( + exec_ctx, c->inner.creds_array[i], md_array, GRPC_ERROR_REF(error)); + } + GRPC_ERROR_UNREF(error); } static grpc_call_credentials_vtable composite_call_credentials_vtable = { - composite_call_destruct, composite_call_get_request_metadata}; + composite_call_destruct, composite_call_get_request_metadata, + composite_call_cancel_get_request_metadata}; static grpc_call_credentials_array get_creds_array( grpc_call_credentials **creds_addr) { diff --git a/src/core/lib/security/credentials/credentials.c b/src/core/lib/security/credentials/credentials.c index b1f1e82076c..8a67c9865be 100644 --- a/src/core/lib/security/credentials/credentials.c +++ b/src/core/lib/security/credentials/credentials.c @@ -38,13 +38,10 @@ /* -- Common. -- */ grpc_credentials_metadata_request *grpc_credentials_metadata_request_create( - grpc_call_credentials *creds, grpc_credentials_metadata_cb cb, - void *user_data) { + grpc_call_credentials *creds) { grpc_credentials_metadata_request *r = gpr_zalloc(sizeof(grpc_credentials_metadata_request)); r->creds = grpc_call_credentials_ref(creds); - r->cb = cb; - r->user_data = user_data; return r; } @@ -104,18 +101,25 @@ void grpc_call_credentials_release(grpc_call_credentials *creds) { grpc_exec_ctx_finish(&exec_ctx); } -void grpc_call_credentials_get_request_metadata( +bool grpc_call_credentials_get_request_metadata( grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, grpc_polling_entity *pollent, grpc_auth_metadata_context context, - grpc_credentials_metadata_cb cb, void *user_data) { + grpc_credentials_mdelem_array *md_array, grpc_closure *on_request_metadata, + grpc_error **error) { if (creds == NULL || creds->vtable->get_request_metadata == NULL) { - if (cb != NULL) { - cb(exec_ctx, user_data, NULL, 0, GRPC_CREDENTIALS_OK, NULL); - } + return true; + } + return creds->vtable->get_request_metadata( + exec_ctx, creds, pollent, context, md_array, on_request_metadata, error); +} + +void grpc_call_credentials_cancel_get_request_metadata( + grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, + grpc_credentials_mdelem_array *md_array, grpc_error *error) { + if (creds == NULL || creds->vtable->cancel_get_request_metadata == NULL) { return; } - creds->vtable->get_request_metadata(exec_ctx, creds, pollent, context, cb, - user_data); + creds->vtable->cancel_get_request_metadata(exec_ctx, creds, md_array, error); } grpc_security_status grpc_channel_credentials_create_security_connector( diff --git a/src/core/lib/security/credentials/credentials.h b/src/core/lib/security/credentials/credentials.h index c45c2e957cc..04a54b0ca83 100644 --- a/src/core/lib/security/credentials/credentials.h +++ b/src/core/lib/security/credentials/credentials.h @@ -138,48 +138,39 @@ grpc_channel_credentials *grpc_channel_credentials_from_arg( grpc_channel_credentials *grpc_channel_credentials_find_in_args( const grpc_channel_args *args); -/* --- grpc_credentials_md. --- */ +/* --- grpc_credentials_mdelem_array. --- */ typedef struct { - grpc_slice key; - grpc_slice value; -} grpc_credentials_md; + grpc_mdelem *md; + size_t size; +} grpc_credentials_mdelem_array; -typedef struct { - grpc_credentials_md *entries; - size_t num_entries; - size_t allocated; - gpr_refcount refcount; -} grpc_credentials_md_store; +/// Takes a new ref to \a md. +void grpc_credentials_mdelem_array_add(grpc_credentials_mdelem_array *list, + grpc_mdelem md); -grpc_credentials_md_store *grpc_credentials_md_store_create( - size_t initial_capacity); +/// Appends all elements from \a src to \a dst, taking a new ref to each one. +void grpc_credentials_mdelem_array_append(grpc_credentials_mdelem_array *dst, + grpc_credentials_mdelem_array *src); -/* Will ref key and value. */ -void grpc_credentials_md_store_add(grpc_credentials_md_store *store, - grpc_slice key, grpc_slice value); -void grpc_credentials_md_store_add_cstrings(grpc_credentials_md_store *store, - const char *key, const char *value); -grpc_credentials_md_store *grpc_credentials_md_store_ref( - grpc_credentials_md_store *store); -void grpc_credentials_md_store_unref(grpc_exec_ctx *exec_ctx, - grpc_credentials_md_store *store); +void grpc_credentials_mdelem_array_destroy(grpc_exec_ctx *exec_ctx, + grpc_credentials_mdelem_array *list); /* --- grpc_call_credentials. --- */ -/* error_details must be NULL if status is GRPC_CREDENTIALS_OK. */ -typedef void (*grpc_credentials_metadata_cb)( - grpc_exec_ctx *exec_ctx, void *user_data, grpc_credentials_md *md_elems, - size_t num_md, grpc_credentials_status status, const char *error_details); - typedef struct { void (*destruct)(grpc_exec_ctx *exec_ctx, grpc_call_credentials *c); - void (*get_request_metadata)(grpc_exec_ctx *exec_ctx, + bool (*get_request_metadata)(grpc_exec_ctx *exec_ctx, grpc_call_credentials *c, grpc_polling_entity *pollent, grpc_auth_metadata_context context, - grpc_credentials_metadata_cb cb, - void *user_data); + grpc_credentials_mdelem_array *md_array, + grpc_closure *on_request_metadata, + grpc_error **error); + void (*cancel_get_request_metadata)(grpc_exec_ctx *exec_ctx, + grpc_call_credentials *c, + grpc_credentials_mdelem_array *md_array, + grpc_error *error); } grpc_call_credentials_vtable; struct grpc_call_credentials { @@ -191,15 +182,29 @@ struct grpc_call_credentials { grpc_call_credentials *grpc_call_credentials_ref(grpc_call_credentials *creds); void grpc_call_credentials_unref(grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds); -void grpc_call_credentials_get_request_metadata( + +/// Returns true if completed synchronously, in which case \a error will +/// be set to indicate the result. Otherwise, \a on_request_metadata will +/// be invoked asynchronously when complete. \a md_array will be populated +/// with the resulting metadata once complete. +bool grpc_call_credentials_get_request_metadata( grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, grpc_polling_entity *pollent, grpc_auth_metadata_context context, - grpc_credentials_metadata_cb cb, void *user_data); + grpc_credentials_mdelem_array *md_array, grpc_closure *on_request_metadata, + grpc_error **error); + +/// Cancels a pending asynchronous operation started by +/// grpc_call_credentials_get_request_metadata() with the corresponding +/// value of \a md_array. +void grpc_call_credentials_cancel_get_request_metadata( + grpc_exec_ctx *exec_ctx, grpc_call_credentials *c, + grpc_credentials_mdelem_array *md_array, grpc_error *error); /* Metadata-only credentials with the specified key and value where asynchronicity can be simulated for testing. */ grpc_call_credentials *grpc_md_only_test_credentials_create( - const char *md_key, const char *md_value, int is_async); + grpc_exec_ctx *exec_ctx, const char *md_key, const char *md_value, + bool is_async); /* --- grpc_server_credentials. --- */ @@ -238,14 +243,11 @@ grpc_server_credentials *grpc_find_server_credentials_in_args( typedef struct { grpc_call_credentials *creds; - grpc_credentials_metadata_cb cb; grpc_http_response response; - void *user_data; } grpc_credentials_metadata_request; grpc_credentials_metadata_request *grpc_credentials_metadata_request_create( - grpc_call_credentials *creds, grpc_credentials_metadata_cb cb, - void *user_data); + grpc_call_credentials *creds); void grpc_credentials_metadata_request_destroy( grpc_exec_ctx *exec_ctx, grpc_credentials_metadata_request *r); diff --git a/src/core/lib/security/credentials/credentials_metadata.c b/src/core/lib/security/credentials/credentials_metadata.c index fcfdd52d20b..ccd39e610f3 100644 --- a/src/core/lib/security/credentials/credentials_metadata.c +++ b/src/core/lib/security/credentials/credentials_metadata.c @@ -24,65 +24,36 @@ #include "src/core/lib/slice/slice_internal.h" -static void store_ensure_capacity(grpc_credentials_md_store *store) { - if (store->num_entries == store->allocated) { - store->allocated = (store->allocated == 0) ? 1 : store->allocated * 2; - store->entries = gpr_realloc( - store->entries, store->allocated * sizeof(grpc_credentials_md)); +static void mdelem_list_ensure_capacity(grpc_credentials_mdelem_array *list, + size_t additional_space_needed) { + size_t target_size = list->size + additional_space_needed; + // Find the next power of two greater than the target size (i.e., + // whenever we add more space, we double what we already have). + size_t new_size = 2; + while (new_size < target_size) { + new_size *= 2; } + list->md = gpr_realloc(list->md, sizeof(grpc_mdelem) * new_size); } -grpc_credentials_md_store *grpc_credentials_md_store_create( - size_t initial_capacity) { - grpc_credentials_md_store *store = - gpr_zalloc(sizeof(grpc_credentials_md_store)); - if (initial_capacity > 0) { - store->entries = gpr_malloc(initial_capacity * sizeof(grpc_credentials_md)); - store->allocated = initial_capacity; - } - gpr_ref_init(&store->refcount, 1); - return store; -} - -void grpc_credentials_md_store_add(grpc_credentials_md_store *store, - grpc_slice key, grpc_slice value) { - if (store == NULL) return; - store_ensure_capacity(store); - store->entries[store->num_entries].key = grpc_slice_ref_internal(key); - store->entries[store->num_entries].value = grpc_slice_ref_internal(value); - store->num_entries++; +void grpc_credentials_mdelem_array_add(grpc_credentials_mdelem_array *list, + grpc_mdelem md) { + mdelem_list_ensure_capacity(list, 1); + list->md[list->size++] = GRPC_MDELEM_REF(md); } -void grpc_credentials_md_store_add_cstrings(grpc_credentials_md_store *store, - const char *key, - const char *value) { - if (store == NULL) return; - store_ensure_capacity(store); - store->entries[store->num_entries].key = grpc_slice_from_copied_string(key); - store->entries[store->num_entries].value = - grpc_slice_from_copied_string(value); - store->num_entries++; -} - -grpc_credentials_md_store *grpc_credentials_md_store_ref( - grpc_credentials_md_store *store) { - if (store == NULL) return NULL; - gpr_ref(&store->refcount); - return store; +void grpc_credentials_mdelem_array_append(grpc_credentials_mdelem_array *dst, + grpc_credentials_mdelem_array *src) { + mdelem_list_ensure_capacity(dst, src->size); + for (size_t i = 0; i < src->size; ++i) { + dst->md[dst->size++] = GRPC_MDELEM_REF(src->md[i]); + } } -void grpc_credentials_md_store_unref(grpc_exec_ctx *exec_ctx, - grpc_credentials_md_store *store) { - if (store == NULL) return; - if (gpr_unref(&store->refcount)) { - if (store->entries != NULL) { - size_t i; - for (i = 0; i < store->num_entries; i++) { - grpc_slice_unref_internal(exec_ctx, store->entries[i].key); - grpc_slice_unref_internal(exec_ctx, store->entries[i].value); - } - gpr_free(store->entries); - } - gpr_free(store); +void grpc_credentials_mdelem_array_destroy( + grpc_exec_ctx *exec_ctx, grpc_credentials_mdelem_array *list) { + for (size_t i = 0; i < list->size; ++i) { + GRPC_MDELEM_UNREF(exec_ctx, list->md[i]); } + gpr_free(list->md); } diff --git a/src/core/lib/security/credentials/fake/fake_credentials.c b/src/core/lib/security/credentials/fake/fake_credentials.c index 67e74f7b921..ac9017850fe 100644 --- a/src/core/lib/security/credentials/fake/fake_credentials.c +++ b/src/core/lib/security/credentials/fake/fake_credentials.c @@ -98,49 +98,44 @@ const char *grpc_fake_transport_get_expected_targets( static void md_only_test_destruct(grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds) { grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)creds; - grpc_credentials_md_store_unref(exec_ctx, c->md_store); + GRPC_MDELEM_UNREF(exec_ctx, c->md); } -static void on_simulated_token_fetch_done(grpc_exec_ctx *exec_ctx, - void *user_data, grpc_error *error) { - grpc_credentials_metadata_request *r = - (grpc_credentials_metadata_request *)user_data; - grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)r->creds; - r->cb(exec_ctx, r->user_data, c->md_store->entries, c->md_store->num_entries, - GRPC_CREDENTIALS_OK, NULL); - grpc_credentials_metadata_request_destroy(exec_ctx, r); -} - -static void md_only_test_get_request_metadata( +static bool md_only_test_get_request_metadata( grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, grpc_polling_entity *pollent, grpc_auth_metadata_context context, - grpc_credentials_metadata_cb cb, void *user_data) { + grpc_credentials_mdelem_array *md_array, grpc_closure *on_request_metadata, + grpc_error **error) { grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)creds; - + grpc_credentials_mdelem_array_add(md_array, c->md); if (c->is_async) { - grpc_credentials_metadata_request *cb_arg = - grpc_credentials_metadata_request_create(creds, cb, user_data); - GRPC_CLOSURE_SCHED(exec_ctx, - GRPC_CLOSURE_CREATE(on_simulated_token_fetch_done, - cb_arg, grpc_executor_scheduler), - GRPC_ERROR_NONE); - } else { - cb(exec_ctx, user_data, c->md_store->entries, 1, GRPC_CREDENTIALS_OK, NULL); + GRPC_CLOSURE_SCHED(exec_ctx, on_request_metadata, GRPC_ERROR_NONE); + return false; } + return true; +} + +static void md_only_test_cancel_get_request_metadata( + grpc_exec_ctx *exec_ctx, grpc_call_credentials *c, + grpc_credentials_mdelem_array *md_array, grpc_error *error) { + GRPC_ERROR_UNREF(error); } static grpc_call_credentials_vtable md_only_test_vtable = { - md_only_test_destruct, md_only_test_get_request_metadata}; + md_only_test_destruct, md_only_test_get_request_metadata, + md_only_test_cancel_get_request_metadata}; grpc_call_credentials *grpc_md_only_test_credentials_create( - const char *md_key, const char *md_value, int is_async) { + grpc_exec_ctx *exec_ctx, const char *md_key, const char *md_value, + bool is_async) { grpc_md_only_test_credentials *c = gpr_zalloc(sizeof(grpc_md_only_test_credentials)); c->base.type = GRPC_CALL_CREDENTIALS_TYPE_OAUTH2; c->base.vtable = &md_only_test_vtable; gpr_ref_init(&c->base.refcount, 1); - c->md_store = grpc_credentials_md_store_create(1); - grpc_credentials_md_store_add_cstrings(c->md_store, md_key, md_value); + c->md = + grpc_mdelem_from_slices(exec_ctx, grpc_slice_from_copied_string(md_key), + grpc_slice_from_copied_string(md_value)); c->is_async = is_async; return &c->base; } diff --git a/src/core/lib/security/credentials/fake/fake_credentials.h b/src/core/lib/security/credentials/fake/fake_credentials.h index fae7a6a9c45..aa0f3b6e207 100644 --- a/src/core/lib/security/credentials/fake/fake_credentials.h +++ b/src/core/lib/security/credentials/fake/fake_credentials.h @@ -52,8 +52,8 @@ const char *grpc_fake_transport_get_expected_targets( typedef struct { grpc_call_credentials base; - grpc_credentials_md_store *md_store; - int is_async; + grpc_mdelem md; + bool is_async; } grpc_md_only_test_credentials; #endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_FAKE_FAKE_CREDENTIALS_H */ diff --git a/src/core/lib/security/credentials/iam/iam_credentials.c b/src/core/lib/security/credentials/iam/iam_credentials.c index 4b32c5a047c..3de8319d98a 100644 --- a/src/core/lib/security/credentials/iam/iam_credentials.c +++ b/src/core/lib/security/credentials/iam/iam_credentials.c @@ -30,26 +30,33 @@ static void iam_destruct(grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds) { grpc_google_iam_credentials *c = (grpc_google_iam_credentials *)creds; - grpc_credentials_md_store_unref(exec_ctx, c->iam_md); + grpc_credentials_mdelem_array_destroy(exec_ctx, &c->md_array); } -static void iam_get_request_metadata(grpc_exec_ctx *exec_ctx, +static bool iam_get_request_metadata(grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, grpc_polling_entity *pollent, grpc_auth_metadata_context context, - grpc_credentials_metadata_cb cb, - void *user_data) { + grpc_credentials_mdelem_array *md_array, + grpc_closure *on_request_metadata, + grpc_error **error) { grpc_google_iam_credentials *c = (grpc_google_iam_credentials *)creds; - cb(exec_ctx, user_data, c->iam_md->entries, c->iam_md->num_entries, - GRPC_CREDENTIALS_OK, NULL); + grpc_credentials_mdelem_array_append(md_array, &c->md_array); + return true; } -static grpc_call_credentials_vtable iam_vtable = {iam_destruct, - iam_get_request_metadata}; +static void iam_cancel_get_request_metadata( + grpc_exec_ctx *exec_ctx, grpc_call_credentials *c, + grpc_credentials_mdelem_array *md_array, grpc_error *error) { + GRPC_ERROR_UNREF(error); +} + +static grpc_call_credentials_vtable iam_vtable = { + iam_destruct, iam_get_request_metadata, iam_cancel_get_request_metadata}; grpc_call_credentials *grpc_google_iam_credentials_create( const char *token, const char *authority_selector, void *reserved) { - grpc_google_iam_credentials *c; + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; GRPC_API_TRACE( "grpc_iam_credentials_create(token=%s, authority_selector=%s, " "reserved=%p)", @@ -57,14 +64,22 @@ grpc_call_credentials *grpc_google_iam_credentials_create( GPR_ASSERT(reserved == NULL); GPR_ASSERT(token != NULL); GPR_ASSERT(authority_selector != NULL); - c = gpr_zalloc(sizeof(grpc_google_iam_credentials)); + grpc_google_iam_credentials *c = gpr_zalloc(sizeof(*c)); c->base.type = GRPC_CALL_CREDENTIALS_TYPE_IAM; c->base.vtable = &iam_vtable; gpr_ref_init(&c->base.refcount, 1); - c->iam_md = grpc_credentials_md_store_create(2); - grpc_credentials_md_store_add_cstrings( - c->iam_md, GRPC_IAM_AUTHORIZATION_TOKEN_METADATA_KEY, token); - grpc_credentials_md_store_add_cstrings( - c->iam_md, GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY, authority_selector); + grpc_mdelem md = grpc_mdelem_from_slices( + &exec_ctx, + grpc_slice_from_static_string(GRPC_IAM_AUTHORIZATION_TOKEN_METADATA_KEY), + grpc_slice_from_copied_string(token)); + grpc_credentials_mdelem_array_add(&c->md_array, md); + GRPC_MDELEM_UNREF(&exec_ctx, md); + md = grpc_mdelem_from_slices( + &exec_ctx, + grpc_slice_from_static_string(GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY), + grpc_slice_from_copied_string(authority_selector)); + grpc_credentials_mdelem_array_add(&c->md_array, md); + GRPC_MDELEM_UNREF(&exec_ctx, md); + grpc_exec_ctx_finish(&exec_ctx); return &c->base; } diff --git a/src/core/lib/security/credentials/iam/iam_credentials.h b/src/core/lib/security/credentials/iam/iam_credentials.h index fff3c6d2ca1..5e3cf65bad4 100644 --- a/src/core/lib/security/credentials/iam/iam_credentials.h +++ b/src/core/lib/security/credentials/iam/iam_credentials.h @@ -23,7 +23,7 @@ typedef struct { grpc_call_credentials base; - grpc_credentials_md_store *iam_md; + grpc_credentials_mdelem_array md_array; } grpc_google_iam_credentials; #endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_IAM_IAM_CREDENTIALS_H */ diff --git a/src/core/lib/security/credentials/jwt/jwt_credentials.c b/src/core/lib/security/credentials/jwt/jwt_credentials.c index 4357657defc..02c82e99ba8 100644 --- a/src/core/lib/security/credentials/jwt/jwt_credentials.c +++ b/src/core/lib/security/credentials/jwt/jwt_credentials.c @@ -29,10 +29,8 @@ static void jwt_reset_cache(grpc_exec_ctx *exec_ctx, grpc_service_account_jwt_access_credentials *c) { - if (c->cached.jwt_md != NULL) { - grpc_credentials_md_store_unref(exec_ctx, c->cached.jwt_md); - c->cached.jwt_md = NULL; - } + GRPC_MDELEM_UNREF(exec_ctx, c->cached.jwt_md); + c->cached.jwt_md = GRPC_MDNULL; if (c->cached.service_url != NULL) { gpr_free(c->cached.service_url); c->cached.service_url = NULL; @@ -49,33 +47,34 @@ static void jwt_destruct(grpc_exec_ctx *exec_ctx, gpr_mu_destroy(&c->cache_mu); } -static void jwt_get_request_metadata(grpc_exec_ctx *exec_ctx, +static bool jwt_get_request_metadata(grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, grpc_polling_entity *pollent, grpc_auth_metadata_context context, - grpc_credentials_metadata_cb cb, - void *user_data) { + grpc_credentials_mdelem_array *md_array, + grpc_closure *on_request_metadata, + grpc_error **error) { grpc_service_account_jwt_access_credentials *c = (grpc_service_account_jwt_access_credentials *)creds; gpr_timespec refresh_threshold = gpr_time_from_seconds( GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS, GPR_TIMESPAN); /* See if we can return a cached jwt. */ - grpc_credentials_md_store *jwt_md = NULL; + grpc_mdelem jwt_md = GRPC_MDNULL; { gpr_mu_lock(&c->cache_mu); if (c->cached.service_url != NULL && strcmp(c->cached.service_url, context.service_url) == 0 && - c->cached.jwt_md != NULL && + !GRPC_MDISNULL(c->cached.jwt_md) && (gpr_time_cmp(gpr_time_sub(c->cached.jwt_expiration, gpr_now(GPR_CLOCK_REALTIME)), refresh_threshold) > 0)) { - jwt_md = grpc_credentials_md_store_ref(c->cached.jwt_md); + jwt_md = GRPC_MDELEM_REF(c->cached.jwt_md); } gpr_mu_unlock(&c->cache_mu); } - if (jwt_md == NULL) { + if (GRPC_MDISNULL(jwt_md)) { char *jwt = NULL; /* Generate a new jwt. */ gpr_mu_lock(&c->cache_mu); @@ -89,27 +88,33 @@ static void jwt_get_request_metadata(grpc_exec_ctx *exec_ctx, c->cached.jwt_expiration = gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), c->jwt_lifetime); c->cached.service_url = gpr_strdup(context.service_url); - c->cached.jwt_md = grpc_credentials_md_store_create(1); - grpc_credentials_md_store_add_cstrings( - c->cached.jwt_md, GRPC_AUTHORIZATION_METADATA_KEY, md_value); + c->cached.jwt_md = grpc_mdelem_from_slices( + exec_ctx, + grpc_slice_from_static_string(GRPC_AUTHORIZATION_METADATA_KEY), + grpc_slice_from_copied_string(md_value)); gpr_free(md_value); - jwt_md = grpc_credentials_md_store_ref(c->cached.jwt_md); + jwt_md = GRPC_MDELEM_REF(c->cached.jwt_md); } gpr_mu_unlock(&c->cache_mu); } - if (jwt_md != NULL) { - cb(exec_ctx, user_data, jwt_md->entries, jwt_md->num_entries, - GRPC_CREDENTIALS_OK, NULL); - grpc_credentials_md_store_unref(exec_ctx, jwt_md); + if (!GRPC_MDISNULL(jwt_md)) { + grpc_credentials_mdelem_array_add(md_array, jwt_md); + GRPC_MDELEM_UNREF(exec_ctx, jwt_md); } else { - cb(exec_ctx, user_data, NULL, 0, GRPC_CREDENTIALS_ERROR, - "Could not generate JWT."); + *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Could not generate JWT."); } + return true; +} + +static void jwt_cancel_get_request_metadata( + grpc_exec_ctx *exec_ctx, grpc_call_credentials *c, + grpc_credentials_mdelem_array *md_array, grpc_error *error) { + GRPC_ERROR_UNREF(error); } -static grpc_call_credentials_vtable jwt_vtable = {jwt_destruct, - jwt_get_request_metadata}; +static grpc_call_credentials_vtable jwt_vtable = { + jwt_destruct, jwt_get_request_metadata, jwt_cancel_get_request_metadata}; grpc_call_credentials * grpc_service_account_jwt_access_credentials_create_from_auth_json_key( diff --git a/src/core/lib/security/credentials/jwt/jwt_credentials.h b/src/core/lib/security/credentials/jwt/jwt_credentials.h index 6e461f17156..07f4022669d 100644 --- a/src/core/lib/security/credentials/jwt/jwt_credentials.h +++ b/src/core/lib/security/credentials/jwt/jwt_credentials.h @@ -29,7 +29,7 @@ typedef struct { // the service_url for a more sophisticated one. gpr_mu cache_mu; struct { - grpc_credentials_md_store *jwt_md; + grpc_mdelem jwt_md; char *service_url; gpr_timespec jwt_expiration; } cached; diff --git a/src/core/lib/security/credentials/oauth2/oauth2_credentials.c b/src/core/lib/security/credentials/oauth2/oauth2_credentials.c index 9de561b3101..ffa941bb9e9 100644 --- a/src/core/lib/security/credentials/oauth2/oauth2_credentials.c +++ b/src/core/lib/security/credentials/oauth2/oauth2_credentials.c @@ -107,7 +107,7 @@ static void oauth2_token_fetcher_destruct(grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds) { grpc_oauth2_token_fetcher_credentials *c = (grpc_oauth2_token_fetcher_credentials *)creds; - grpc_credentials_md_store_unref(exec_ctx, c->access_token_md); + GRPC_MDELEM_UNREF(exec_ctx, c->access_token_md); gpr_mu_destroy(&c->mu); grpc_httpcli_context_destroy(exec_ctx, &c->httpcli_context); } @@ -115,7 +115,7 @@ static void oauth2_token_fetcher_destruct(grpc_exec_ctx *exec_ctx, grpc_credentials_status grpc_oauth2_token_fetcher_credentials_parse_server_response( grpc_exec_ctx *exec_ctx, const grpc_http_response *response, - grpc_credentials_md_store **token_md, gpr_timespec *token_lifetime) { + grpc_mdelem *token_md, gpr_timespec *token_lifetime) { char *null_terminated_body = NULL; char *new_access_token = NULL; grpc_credentials_status status = GRPC_CREDENTIALS_OK; @@ -184,17 +184,18 @@ grpc_oauth2_token_fetcher_credentials_parse_server_response( token_lifetime->tv_sec = strtol(expires_in->value, NULL, 10); token_lifetime->tv_nsec = 0; token_lifetime->clock_type = GPR_TIMESPAN; - if (*token_md != NULL) grpc_credentials_md_store_unref(exec_ctx, *token_md); - *token_md = grpc_credentials_md_store_create(1); - grpc_credentials_md_store_add_cstrings( - *token_md, GRPC_AUTHORIZATION_METADATA_KEY, new_access_token); + if (!GRPC_MDISNULL(*token_md)) GRPC_MDELEM_UNREF(exec_ctx, *token_md); + *token_md = grpc_mdelem_from_slices( + exec_ctx, + grpc_slice_from_static_string(GRPC_AUTHORIZATION_METADATA_KEY), + grpc_slice_from_copied_string(new_access_token)); status = GRPC_CREDENTIALS_OK; } end: - if (status != GRPC_CREDENTIALS_OK && (*token_md != NULL)) { - grpc_credentials_md_store_unref(exec_ctx, *token_md); - *token_md = NULL; + if (status != GRPC_CREDENTIALS_OK && !GRPC_MDISNULL(*token_md)) { + GRPC_MDELEM_UNREF(exec_ctx, *token_md); + *token_md = GRPC_MDNULL; } if (null_terminated_body != NULL) gpr_free(null_terminated_body); if (new_access_token != NULL) gpr_free(new_access_token); @@ -205,63 +206,124 @@ end: static void on_oauth2_token_fetcher_http_response(grpc_exec_ctx *exec_ctx, void *user_data, grpc_error *error) { + GRPC_LOG_IF_ERROR("oauth_fetch", GRPC_ERROR_REF(error)); grpc_credentials_metadata_request *r = (grpc_credentials_metadata_request *)user_data; grpc_oauth2_token_fetcher_credentials *c = (grpc_oauth2_token_fetcher_credentials *)r->creds; + grpc_mdelem access_token_md = GRPC_MDNULL; gpr_timespec token_lifetime; - grpc_credentials_status status; - - GRPC_LOG_IF_ERROR("oauth_fetch", GRPC_ERROR_REF(error)); - + grpc_credentials_status status = + grpc_oauth2_token_fetcher_credentials_parse_server_response( + exec_ctx, &r->response, &access_token_md, &token_lifetime); + // Update cache and grab list of pending requests. gpr_mu_lock(&c->mu); - status = grpc_oauth2_token_fetcher_credentials_parse_server_response( - exec_ctx, &r->response, &c->access_token_md, &token_lifetime); - if (status == GRPC_CREDENTIALS_OK) { - c->token_expiration = - gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), token_lifetime); - r->cb(exec_ctx, r->user_data, c->access_token_md->entries, - c->access_token_md->num_entries, GRPC_CREDENTIALS_OK, NULL); - } else { - c->token_expiration = gpr_inf_past(GPR_CLOCK_REALTIME); - r->cb(exec_ctx, r->user_data, NULL, 0, status, - "Error occured when fetching oauth2 token."); - } + c->token_fetch_pending = false; + c->access_token_md = GRPC_MDELEM_REF(access_token_md); + c->token_expiration = + status == GRPC_CREDENTIALS_OK + ? gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), token_lifetime) + : gpr_inf_past(GPR_CLOCK_REALTIME); + grpc_oauth2_pending_get_request_metadata *pending_request = + c->pending_requests; + c->pending_requests = NULL; gpr_mu_unlock(&c->mu); + // Invoke callbacks for all pending requests. + while (pending_request != NULL) { + if (status == GRPC_CREDENTIALS_OK) { + grpc_credentials_mdelem_array_add(pending_request->md_array, + access_token_md); + } else { + error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( + "Error occured when fetching oauth2 token.", &error, 1); + } + GRPC_CLOSURE_SCHED(exec_ctx, pending_request->on_request_metadata, error); + grpc_oauth2_pending_get_request_metadata *prev = pending_request; + pending_request = pending_request->next; + gpr_free(prev); + } + GRPC_MDELEM_UNREF(exec_ctx, access_token_md); + grpc_call_credentials_unref(exec_ctx, r->creds); grpc_credentials_metadata_request_destroy(exec_ctx, r); } -static void oauth2_token_fetcher_get_request_metadata( +static bool oauth2_token_fetcher_get_request_metadata( grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, grpc_polling_entity *pollent, grpc_auth_metadata_context context, - grpc_credentials_metadata_cb cb, void *user_data) { + grpc_credentials_mdelem_array *md_array, grpc_closure *on_request_metadata, + grpc_error **error) { grpc_oauth2_token_fetcher_credentials *c = (grpc_oauth2_token_fetcher_credentials *)creds; + // Check if we can use the cached token. gpr_timespec refresh_threshold = gpr_time_from_seconds( GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS, GPR_TIMESPAN); - grpc_credentials_md_store *cached_access_token_md = NULL; - { - gpr_mu_lock(&c->mu); - if (c->access_token_md != NULL && - (gpr_time_cmp( - gpr_time_sub(c->token_expiration, gpr_now(GPR_CLOCK_REALTIME)), - refresh_threshold) > 0)) { - cached_access_token_md = - grpc_credentials_md_store_ref(c->access_token_md); - } + grpc_mdelem cached_access_token_md = GRPC_MDNULL; + gpr_mu_lock(&c->mu); + if (!GRPC_MDISNULL(c->access_token_md) && + (gpr_time_cmp( + gpr_time_sub(c->token_expiration, gpr_now(GPR_CLOCK_REALTIME)), + refresh_threshold) > 0)) { + cached_access_token_md = GRPC_MDELEM_REF(c->access_token_md); + } + if (!GRPC_MDISNULL(cached_access_token_md)) { gpr_mu_unlock(&c->mu); + grpc_credentials_mdelem_array_add(md_array, cached_access_token_md); + GRPC_MDELEM_UNREF(exec_ctx, cached_access_token_md); + return true; } - if (cached_access_token_md != NULL) { - cb(exec_ctx, user_data, cached_access_token_md->entries, - cached_access_token_md->num_entries, GRPC_CREDENTIALS_OK, NULL); - grpc_credentials_md_store_unref(exec_ctx, cached_access_token_md); - } else { - c->fetch_func( - exec_ctx, - grpc_credentials_metadata_request_create(creds, cb, user_data), - &c->httpcli_context, pollent, on_oauth2_token_fetcher_http_response, - gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), refresh_threshold)); + // Couldn't get the token from the cache. + // Add request to c->pending_requests and start a new fetch if needed. + grpc_oauth2_pending_get_request_metadata *pending_request = + (grpc_oauth2_pending_get_request_metadata *)gpr_malloc( + sizeof(*pending_request)); + pending_request->md_array = md_array; + pending_request->on_request_metadata = on_request_metadata; + pending_request->next = c->pending_requests; + c->pending_requests = pending_request; + bool start_fetch = false; + if (!c->token_fetch_pending) { + c->token_fetch_pending = true; + start_fetch = true; + } + gpr_mu_unlock(&c->mu); + if (start_fetch) { + grpc_call_credentials_ref(creds); + c->fetch_func(exec_ctx, grpc_credentials_metadata_request_create(creds), + &c->httpcli_context, pollent, + on_oauth2_token_fetcher_http_response, + gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), refresh_threshold)); } + return false; +} + +static void oauth2_token_fetcher_cancel_get_request_metadata( + grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, + grpc_credentials_mdelem_array *md_array, grpc_error *error) { + grpc_oauth2_token_fetcher_credentials *c = + (grpc_oauth2_token_fetcher_credentials *)creds; + gpr_mu_lock(&c->mu); + grpc_oauth2_pending_get_request_metadata *prev = NULL; + grpc_oauth2_pending_get_request_metadata *pending_request = + c->pending_requests; + while (pending_request != NULL) { + if (pending_request->md_array == md_array) { + // Remove matching pending request from the list. + if (prev != NULL) { + prev->next = pending_request->next; + } else { + c->pending_requests = pending_request->next; + } + // Invoke the callback immediately with an error. + GRPC_CLOSURE_SCHED(exec_ctx, pending_request->on_request_metadata, + GRPC_ERROR_REF(error)); + gpr_free(pending_request); + break; + } + prev = pending_request; + pending_request = pending_request->next; + } + gpr_mu_unlock(&c->mu); + GRPC_ERROR_UNREF(error); } static void init_oauth2_token_fetcher(grpc_oauth2_token_fetcher_credentials *c, @@ -280,7 +342,8 @@ static void init_oauth2_token_fetcher(grpc_oauth2_token_fetcher_credentials *c, // static grpc_call_credentials_vtable compute_engine_vtable = { - oauth2_token_fetcher_destruct, oauth2_token_fetcher_get_request_metadata}; + oauth2_token_fetcher_destruct, oauth2_token_fetcher_get_request_metadata, + oauth2_token_fetcher_cancel_get_request_metadata}; static void compute_engine_fetch_oauth2( grpc_exec_ctx *exec_ctx, grpc_credentials_metadata_request *metadata_req, @@ -301,7 +364,6 @@ static void compute_engine_fetch_oauth2( grpc_httpcli_get( exec_ctx, httpcli_context, pollent, resource_quota, &request, deadline, GRPC_CLOSURE_CREATE(response_cb, metadata_req, grpc_schedule_on_exec_ctx), - &metadata_req->response); grpc_resource_quota_unref_internal(exec_ctx, resource_quota); } @@ -331,7 +393,8 @@ static void refresh_token_destruct(grpc_exec_ctx *exec_ctx, } static grpc_call_credentials_vtable refresh_token_vtable = { - refresh_token_destruct, oauth2_token_fetcher_get_request_metadata}; + refresh_token_destruct, oauth2_token_fetcher_get_request_metadata, + oauth2_token_fetcher_cancel_get_request_metadata}; static void refresh_token_fetch_oauth2( grpc_exec_ctx *exec_ctx, grpc_credentials_metadata_request *metadata_req, @@ -416,26 +479,33 @@ grpc_call_credentials *grpc_google_refresh_token_credentials_create( static void access_token_destruct(grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds) { grpc_access_token_credentials *c = (grpc_access_token_credentials *)creds; - grpc_credentials_md_store_unref(exec_ctx, c->access_token_md); + GRPC_MDELEM_UNREF(exec_ctx, c->access_token_md); } -static void access_token_get_request_metadata( +static bool access_token_get_request_metadata( grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, grpc_polling_entity *pollent, grpc_auth_metadata_context context, - grpc_credentials_metadata_cb cb, void *user_data) { + grpc_credentials_mdelem_array *md_array, grpc_closure *on_request_metadata, + grpc_error **error) { grpc_access_token_credentials *c = (grpc_access_token_credentials *)creds; - cb(exec_ctx, user_data, c->access_token_md->entries, 1, GRPC_CREDENTIALS_OK, - NULL); + grpc_credentials_mdelem_array_add(md_array, c->access_token_md); + return true; +} + +static void access_token_cancel_get_request_metadata( + grpc_exec_ctx *exec_ctx, grpc_call_credentials *c, + grpc_credentials_mdelem_array *md_array, grpc_error *error) { + GRPC_ERROR_UNREF(error); } static grpc_call_credentials_vtable access_token_vtable = { - access_token_destruct, access_token_get_request_metadata}; + access_token_destruct, access_token_get_request_metadata, + access_token_cancel_get_request_metadata}; grpc_call_credentials *grpc_access_token_credentials_create( const char *access_token, void *reserved) { grpc_access_token_credentials *c = gpr_zalloc(sizeof(grpc_access_token_credentials)); - char *token_md_value; GRPC_API_TRACE( "grpc_access_token_credentials_create(access_token=, " "reserved=%p)", @@ -444,10 +514,13 @@ grpc_call_credentials *grpc_access_token_credentials_create( c->base.type = GRPC_CALL_CREDENTIALS_TYPE_OAUTH2; c->base.vtable = &access_token_vtable; gpr_ref_init(&c->base.refcount, 1); - c->access_token_md = grpc_credentials_md_store_create(1); + char *token_md_value; gpr_asprintf(&token_md_value, "Bearer %s", access_token); - grpc_credentials_md_store_add_cstrings( - c->access_token_md, GRPC_AUTHORIZATION_METADATA_KEY, token_md_value); + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + c->access_token_md = grpc_mdelem_from_slices( + &exec_ctx, grpc_slice_from_static_string(GRPC_AUTHORIZATION_METADATA_KEY), + grpc_slice_from_copied_string(token_md_value)); + grpc_exec_ctx_finish(&exec_ctx); gpr_free(token_md_value); return &c->base; } diff --git a/src/core/lib/security/credentials/oauth2/oauth2_credentials.h b/src/core/lib/security/credentials/oauth2/oauth2_credentials.h index 72093afe9e7..9d041a20eaf 100644 --- a/src/core/lib/security/credentials/oauth2/oauth2_credentials.h +++ b/src/core/lib/security/credentials/oauth2/oauth2_credentials.h @@ -58,11 +58,20 @@ typedef void (*grpc_fetch_oauth2_func)(grpc_exec_ctx *exec_ctx, grpc_polling_entity *pollent, grpc_iomgr_cb_func cb, gpr_timespec deadline); + +typedef struct grpc_oauth2_pending_get_request_metadata { + grpc_credentials_mdelem_array *md_array; + grpc_closure *on_request_metadata; + struct grpc_oauth2_pending_get_request_metadata *next; +} grpc_oauth2_pending_get_request_metadata; + typedef struct { grpc_call_credentials base; gpr_mu mu; - grpc_credentials_md_store *access_token_md; + grpc_mdelem access_token_md; gpr_timespec token_expiration; + bool token_fetch_pending; + grpc_oauth2_pending_get_request_metadata *pending_requests; grpc_httpcli_context httpcli_context; grpc_fetch_oauth2_func fetch_func; } grpc_oauth2_token_fetcher_credentials; @@ -76,7 +85,7 @@ typedef struct { // Access token credentials. typedef struct { grpc_call_credentials base; - grpc_credentials_md_store *access_token_md; + grpc_mdelem access_token_md; } grpc_access_token_credentials; // Private constructor for refresh token credentials from an already parsed @@ -89,6 +98,6 @@ grpc_refresh_token_credentials_create_from_auth_refresh_token( grpc_credentials_status grpc_oauth2_token_fetcher_credentials_parse_server_response( grpc_exec_ctx *exec_ctx, const struct grpc_http_response *response, - grpc_credentials_md_store **token_md, gpr_timespec *token_lifetime); + grpc_mdelem *token_md, gpr_timespec *token_lifetime); #endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_OAUTH2_OAUTH2_CREDENTIALS_H */ diff --git a/src/core/lib/security/credentials/plugin/plugin_credentials.c b/src/core/lib/security/credentials/plugin/plugin_credentials.c index 96ebfb4d0d4..73e0c23e0f7 100644 --- a/src/core/lib/security/credentials/plugin/plugin_credentials.c +++ b/src/core/lib/security/credentials/plugin/plugin_credentials.c @@ -31,19 +31,28 @@ #include "src/core/lib/surface/api_trace.h" #include "src/core/lib/surface/validate_metadata.h" -typedef struct { - void *user_data; - grpc_credentials_metadata_cb cb; -} grpc_metadata_plugin_request; - static void plugin_destruct(grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds) { grpc_plugin_credentials *c = (grpc_plugin_credentials *)creds; + gpr_mu_destroy(&c->mu); if (c->plugin.state != NULL && c->plugin.destroy != NULL) { c->plugin.destroy(c->plugin.state); } } +static void pending_request_remove_locked( + grpc_plugin_credentials *c, + grpc_plugin_credentials_pending_request *pending_request) { + if (pending_request->prev == NULL) { + c->pending_requests = pending_request->next; + } else { + pending_request->prev->next = pending_request->next; + } + if (pending_request->next != NULL) { + pending_request->next->prev = pending_request->prev; + } +} + static void plugin_md_request_metadata_ready(void *request, const grpc_metadata *md, size_t num_md, @@ -53,76 +62,117 @@ static void plugin_md_request_metadata_ready(void *request, grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INITIALIZER( GRPC_EXEC_CTX_FLAG_IS_FINISHED | GRPC_EXEC_CTX_FLAG_THREAD_RESOURCE_LOOP, NULL, NULL); - grpc_metadata_plugin_request *r = (grpc_metadata_plugin_request *)request; - if (status != GRPC_STATUS_OK) { - if (error_details != NULL) { - gpr_log(GPR_ERROR, "Getting metadata from plugin failed with error: %s", - error_details); - } - r->cb(&exec_ctx, r->user_data, NULL, 0, GRPC_CREDENTIALS_ERROR, - error_details); - } else { - size_t i; - bool seen_illegal_header = false; - grpc_credentials_md *md_array = NULL; - for (i = 0; i < num_md; i++) { - if (!GRPC_LOG_IF_ERROR("validate_metadata_from_plugin", - grpc_validate_header_key_is_legal(md[i].key))) { - seen_illegal_header = true; - break; - } else if (!grpc_is_binary_header(md[i].key) && - !GRPC_LOG_IF_ERROR( - "validate_metadata_from_plugin", - grpc_validate_header_nonbin_value_is_legal(md[i].value))) { - gpr_log(GPR_ERROR, "Plugin added invalid metadata value."); - seen_illegal_header = true; - break; + grpc_plugin_credentials_pending_request *r = + (grpc_plugin_credentials_pending_request *)request; + // Check if the request has been cancelled. + // If not, remove it from the pending list, so that it cannot be + // cancelled out from under us. + gpr_mu_lock(&r->creds->mu); + if (!r->cancelled) pending_request_remove_locked(r->creds, r); + gpr_mu_unlock(&r->creds->mu); + grpc_call_credentials_unref(&exec_ctx, &r->creds->base); + // If it has not been cancelled, process it. + if (!r->cancelled) { + if (status != GRPC_STATUS_OK) { + char *msg; + gpr_asprintf(&msg, "Getting metadata from plugin failed with error: %s", + error_details); + GRPC_CLOSURE_SCHED(&exec_ctx, r->on_request_metadata, + GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg)); + gpr_free(msg); + } else { + bool seen_illegal_header = false; + for (size_t i = 0; i < num_md; ++i) { + if (!GRPC_LOG_IF_ERROR("validate_metadata_from_plugin", + grpc_validate_header_key_is_legal(md[i].key))) { + seen_illegal_header = true; + break; + } else if (!grpc_is_binary_header(md[i].key) && + !GRPC_LOG_IF_ERROR( + "validate_metadata_from_plugin", + grpc_validate_header_nonbin_value_is_legal( + md[i].value))) { + gpr_log(GPR_ERROR, "Plugin added invalid metadata value."); + seen_illegal_header = true; + break; + } } - } - if (seen_illegal_header) { - r->cb(&exec_ctx, r->user_data, NULL, 0, GRPC_CREDENTIALS_ERROR, - "Illegal metadata"); - } else if (num_md > 0) { - md_array = gpr_malloc(num_md * sizeof(grpc_credentials_md)); - for (i = 0; i < num_md; i++) { - md_array[i].key = grpc_slice_ref_internal(md[i].key); - md_array[i].value = grpc_slice_ref_internal(md[i].value); + if (seen_illegal_header) { + GRPC_CLOSURE_SCHED( + &exec_ctx, r->on_request_metadata, + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Illegal metadata")); + } else { + for (size_t i = 0; i < num_md; ++i) { + grpc_mdelem mdelem = grpc_mdelem_from_slices( + &exec_ctx, grpc_slice_ref_internal(md[i].key), + grpc_slice_ref_internal(md[i].value)); + grpc_credentials_mdelem_array_add(r->md_array, mdelem); + GRPC_MDELEM_UNREF(&exec_ctx, mdelem); + } + GRPC_CLOSURE_SCHED(&exec_ctx, r->on_request_metadata, GRPC_ERROR_NONE); } - r->cb(&exec_ctx, r->user_data, md_array, num_md, GRPC_CREDENTIALS_OK, - NULL); - for (i = 0; i < num_md; i++) { - grpc_slice_unref_internal(&exec_ctx, md_array[i].key); - grpc_slice_unref_internal(&exec_ctx, md_array[i].value); - } - gpr_free(md_array); - } else if (num_md == 0) { - r->cb(&exec_ctx, r->user_data, NULL, 0, GRPC_CREDENTIALS_OK, NULL); } } gpr_free(r); grpc_exec_ctx_finish(&exec_ctx); } -static void plugin_get_request_metadata(grpc_exec_ctx *exec_ctx, +static bool plugin_get_request_metadata(grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, grpc_polling_entity *pollent, grpc_auth_metadata_context context, - grpc_credentials_metadata_cb cb, - void *user_data) { + grpc_credentials_mdelem_array *md_array, + grpc_closure *on_request_metadata, + grpc_error **error) { grpc_plugin_credentials *c = (grpc_plugin_credentials *)creds; if (c->plugin.get_metadata != NULL) { - grpc_metadata_plugin_request *request = gpr_zalloc(sizeof(*request)); - request->user_data = user_data; - request->cb = cb; + // Create pending_request object. + grpc_plugin_credentials_pending_request *pending_request = + (grpc_plugin_credentials_pending_request *)gpr_zalloc( + sizeof(*pending_request)); + pending_request->creds = c; + pending_request->md_array = md_array; + pending_request->on_request_metadata = on_request_metadata; + // Add it to the pending list. + gpr_mu_lock(&c->mu); + if (c->pending_requests != NULL) { + c->pending_requests->prev = pending_request; + } + pending_request->next = c->pending_requests; + c->pending_requests = pending_request; + gpr_mu_unlock(&c->mu); + // Invoke the plugin. The callback holds a ref to us. + grpc_call_credentials_ref(creds); c->plugin.get_metadata(c->plugin.state, context, - plugin_md_request_metadata_ready, request); - } else { - cb(exec_ctx, user_data, NULL, 0, GRPC_CREDENTIALS_OK, NULL); + plugin_md_request_metadata_ready, pending_request); + return false; + } + return true; +} + +static void plugin_cancel_get_request_metadata( + grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, + grpc_credentials_mdelem_array *md_array, grpc_error *error) { + grpc_plugin_credentials *c = (grpc_plugin_credentials *)creds; + gpr_mu_lock(&c->mu); + for (grpc_plugin_credentials_pending_request *pending_request = + c->pending_requests; + pending_request != NULL; pending_request = pending_request->next) { + if (pending_request->md_array == md_array) { + pending_request->cancelled = true; + GRPC_CLOSURE_SCHED(exec_ctx, pending_request->on_request_metadata, + GRPC_ERROR_REF(error)); + pending_request_remove_locked(c, pending_request); + break; + } } + gpr_mu_unlock(&c->mu); + GRPC_ERROR_UNREF(error); } static grpc_call_credentials_vtable plugin_vtable = { - plugin_destruct, plugin_get_request_metadata}; + plugin_destruct, plugin_get_request_metadata, + plugin_cancel_get_request_metadata}; grpc_call_credentials *grpc_metadata_credentials_create_from_plugin( grpc_metadata_credentials_plugin plugin, void *reserved) { @@ -134,5 +184,6 @@ grpc_call_credentials *grpc_metadata_credentials_create_from_plugin( c->base.vtable = &plugin_vtable; gpr_ref_init(&c->base.refcount, 1); c->plugin = plugin; + gpr_mu_init(&c->mu); return &c->base; } diff --git a/src/core/lib/security/credentials/plugin/plugin_credentials.h b/src/core/lib/security/credentials/plugin/plugin_credentials.h index ba3dd76859e..57266d589a4 100644 --- a/src/core/lib/security/credentials/plugin/plugin_credentials.h +++ b/src/core/lib/security/credentials/plugin/plugin_credentials.h @@ -21,10 +21,22 @@ #include "src/core/lib/security/credentials/credentials.h" -typedef struct { +struct grpc_plugin_credentials; + +typedef struct grpc_plugin_credentials_pending_request { + bool cancelled; + struct grpc_plugin_credentials *creds; + grpc_credentials_mdelem_array *md_array; + grpc_closure *on_request_metadata; + struct grpc_plugin_credentials_pending_request *prev; + struct grpc_plugin_credentials_pending_request *next; +} grpc_plugin_credentials_pending_request; + +typedef struct grpc_plugin_credentials { grpc_call_credentials base; grpc_metadata_credentials_plugin plugin; - grpc_credentials_md_store *plugin_md; + gpr_mu mu; + grpc_plugin_credentials_pending_request *pending_requests; } grpc_plugin_credentials; #endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_PLUGIN_PLUGIN_CREDENTIALS_H */ diff --git a/src/core/lib/security/transport/client_auth_filter.c b/src/core/lib/security/transport/client_auth_filter.c index 50a51b31cdb..531a88434f3 100644 --- a/src/core/lib/security/transport/client_auth_filter.c +++ b/src/core/lib/security/transport/client_auth_filter.c @@ -51,8 +51,15 @@ typedef struct { grpc_polling_entity *pollent; gpr_atm security_context_set; gpr_mu security_context_mu; + grpc_credentials_mdelem_array md_array; grpc_linked_mdelem md_links[MAX_CREDENTIALS_METADATA_COUNT]; grpc_auth_metadata_context auth_md_context; + grpc_closure closure; + // Either 0 (no cancellation and no async operation in flight), + // a grpc_closure* (if the lowest bit is 0), + // or a grpc_error* (if the lowest bit is 1). + gpr_atm cancellation_state; + grpc_closure cancel_closure; } call_data; /* We can have a per-channel credentials. */ @@ -61,6 +68,43 @@ typedef struct { grpc_auth_context *auth_context; } channel_data; +static void decode_cancel_state(gpr_atm cancel_state, grpc_closure **func, + grpc_error **error) { + // If the lowest bit is 1, the value is a grpc_error*. + // Otherwise, if non-zdero, the value is a grpc_closure*. + if (cancel_state & 1) { + *error = (grpc_error *)(cancel_state & ~(gpr_atm)1); + } else if (cancel_state != 0) { + *func = (grpc_closure *)cancel_state; + } +} + +static gpr_atm encode_cancel_state_error(grpc_error *error) { + // Set the lowest bit to 1 to indicate that it's an error. + return (gpr_atm)1 | (gpr_atm)error; +} + +// Returns an error if the call has been cancelled. Otherwise, sets the +// cancellation function to be called upon cancellation. +static grpc_error *set_cancel_func(grpc_call_element *elem, + grpc_iomgr_cb_func func) { + call_data *calld = (call_data *)elem->call_data; + // Decode original state. + gpr_atm original_state = gpr_atm_acq_load(&calld->cancellation_state); + grpc_error *original_error = GRPC_ERROR_NONE; + grpc_closure *original_func = NULL; + decode_cancel_state(original_state, &original_func, &original_error); + // If error is set, return it. + if (original_error != GRPC_ERROR_NONE) return GRPC_ERROR_REF(original_error); + // Otherwise, store func. + GRPC_CLOSURE_INIT(&calld->cancel_closure, func, elem, + grpc_schedule_on_exec_ctx); + GPR_ASSERT(((gpr_atm)&calld->cancel_closure & (gpr_atm)1) == 0); + gpr_atm_rel_store(&calld->cancellation_state, + (gpr_atm)&calld->cancel_closure); + return GRPC_ERROR_NONE; +} + static void reset_auth_metadata_context( grpc_auth_metadata_context *auth_md_context) { if (auth_md_context->service_url != NULL) { @@ -86,41 +130,29 @@ static void add_error(grpc_error **combined, grpc_error *error) { *combined = grpc_error_add_child(*combined, error); } -static void on_credentials_metadata(grpc_exec_ctx *exec_ctx, void *user_data, - grpc_credentials_md *md_elems, - size_t num_md, - grpc_credentials_status status, - const char *error_details) { - grpc_transport_stream_op_batch *batch = - (grpc_transport_stream_op_batch *)user_data; +static void on_credentials_metadata(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *input_error) { + grpc_transport_stream_op_batch *batch = (grpc_transport_stream_op_batch *)arg; grpc_call_element *elem = batch->handler_private.extra_arg; call_data *calld = elem->call_data; reset_auth_metadata_context(&calld->auth_md_context); - grpc_error *error = GRPC_ERROR_NONE; - if (status != GRPC_CREDENTIALS_OK) { - error = grpc_error_set_int( - GRPC_ERROR_CREATE_FROM_COPIED_STRING( - error_details != NULL && strlen(error_details) > 0 - ? error_details - : "Credentials failed to get metadata."), - GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAUTHENTICATED); - } else { - GPR_ASSERT(num_md <= MAX_CREDENTIALS_METADATA_COUNT); + grpc_error *error = GRPC_ERROR_REF(input_error); + if (error == GRPC_ERROR_NONE) { + GPR_ASSERT(calld->md_array.size <= MAX_CREDENTIALS_METADATA_COUNT); GPR_ASSERT(batch->send_initial_metadata); grpc_metadata_batch *mdb = batch->payload->send_initial_metadata.send_initial_metadata; - for (size_t i = 0; i < num_md; i++) { - add_error(&error, - grpc_metadata_batch_add_tail( - exec_ctx, mdb, &calld->md_links[i], - grpc_mdelem_from_slices( - exec_ctx, grpc_slice_ref_internal(md_elems[i].key), - grpc_slice_ref_internal(md_elems[i].value)))); + for (size_t i = 0; i < calld->md_array.size; ++i) { + add_error(&error, grpc_metadata_batch_add_tail( + exec_ctx, mdb, &calld->md_links[i], + GRPC_MDELEM_REF(calld->md_array.md[i]))); } } if (error == GRPC_ERROR_NONE) { grpc_call_next_op(exec_ctx, elem, batch); } else { + error = grpc_error_set_int(error, GRPC_ERROR_INT_GRPC_STATUS, + GRPC_STATUS_UNAUTHENTICATED); grpc_transport_stream_op_batch_finish_with_failure(exec_ctx, batch, error); } } @@ -155,6 +187,14 @@ void build_auth_metadata_context(grpc_security_connector *sc, gpr_free(host); } +static void cancel_get_request_metadata(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + grpc_call_element *elem = (grpc_call_element *)arg; + call_data *calld = (call_data *)elem->call_data; + grpc_call_credentials_cancel_get_request_metadata( + exec_ctx, calld->creds, &calld->md_array, GRPC_ERROR_REF(error)); +} + static void send_security_metadata(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, grpc_transport_stream_op_batch *batch) { @@ -193,20 +233,33 @@ static void send_security_metadata(grpc_exec_ctx *exec_ctx, build_auth_metadata_context(&chand->security_connector->base, chand->auth_context, calld); + + grpc_error *cancel_error = set_cancel_func(elem, cancel_get_request_metadata); + if (cancel_error != GRPC_ERROR_NONE) { + grpc_transport_stream_op_batch_finish_with_failure(exec_ctx, batch, + cancel_error); + return; + } GPR_ASSERT(calld->pollent != NULL); - grpc_call_credentials_get_request_metadata( - exec_ctx, calld->creds, calld->pollent, calld->auth_md_context, - on_credentials_metadata, batch); + GRPC_CLOSURE_INIT(&calld->closure, on_credentials_metadata, batch, + grpc_schedule_on_exec_ctx); + grpc_error *error = GRPC_ERROR_NONE; + if (grpc_call_credentials_get_request_metadata( + exec_ctx, calld->creds, calld->pollent, calld->auth_md_context, + &calld->md_array, &calld->closure, &error)) { + // Synchronous return; invoke on_credentials_metadata() directly. + on_credentials_metadata(exec_ctx, batch, error); + GRPC_ERROR_UNREF(error); + } } -static void on_host_checked(grpc_exec_ctx *exec_ctx, void *user_data, - grpc_security_status status) { - grpc_transport_stream_op_batch *batch = - (grpc_transport_stream_op_batch *)user_data; +static void on_host_checked(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + grpc_transport_stream_op_batch *batch = (grpc_transport_stream_op_batch *)arg; grpc_call_element *elem = batch->handler_private.extra_arg; call_data *calld = elem->call_data; - if (status == GRPC_SECURITY_OK) { + if (error == GRPC_ERROR_NONE) { send_security_metadata(exec_ctx, elem, batch); } else { char *error_msg; @@ -223,6 +276,16 @@ static void on_host_checked(grpc_exec_ctx *exec_ctx, void *user_data, } } +static void cancel_check_call_host(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + grpc_call_element *elem = (grpc_call_element *)arg; + call_data *calld = (call_data *)elem->call_data; + channel_data *chand = (channel_data *)elem->channel_data; + grpc_channel_security_connector_cancel_check_call_host( + exec_ctx, chand->security_connector, &calld->closure, + GRPC_ERROR_REF(error)); +} + static void auth_start_transport_stream_op_batch( grpc_exec_ctx *exec_ctx, grpc_call_element *elem, grpc_transport_stream_op_batch *batch) { @@ -232,7 +295,32 @@ static void auth_start_transport_stream_op_batch( call_data *calld = elem->call_data; channel_data *chand = elem->channel_data; - if (!batch->cancel_stream) { + if (batch->cancel_stream) { + while (true) { + // Decode the original cancellation state. + gpr_atm original_state = gpr_atm_acq_load(&calld->cancellation_state); + grpc_error *cancel_error = GRPC_ERROR_NONE; + grpc_closure *func = NULL; + decode_cancel_state(original_state, &func, &cancel_error); + // If we had already set a cancellation error, there's nothing + // more to do. + if (cancel_error != GRPC_ERROR_NONE) break; + // If there's a cancel func, call it. + // Note that even if the cancel func has been changed by some + // other thread between when we decoded it and now, it will just + // be a no-op. + cancel_error = GRPC_ERROR_REF(batch->payload->cancel_stream.cancel_error); + if (func != NULL) { + GRPC_CLOSURE_SCHED(exec_ctx, func, GRPC_ERROR_REF(cancel_error)); + } + // Encode the new error into cancellation state. + if (gpr_atm_full_cas(&calld->cancellation_state, original_state, + encode_cancel_state_error(cancel_error))) { + break; // Success. + } + // The cas failed, so try again. + } + } else { /* double checked lock over security context to ensure it's set once */ if (gpr_atm_acq_load(&calld->security_context_set) == 0) { gpr_mu_lock(&calld->security_context_mu); @@ -277,12 +365,26 @@ static void auth_start_transport_stream_op_batch( } } if (calld->have_host) { - char *call_host = grpc_slice_to_c_string(calld->host); - batch->handler_private.extra_arg = elem; - grpc_channel_security_connector_check_call_host( - exec_ctx, chand->security_connector, call_host, chand->auth_context, - on_host_checked, batch); - gpr_free(call_host); + grpc_error *cancel_error = set_cancel_func(elem, cancel_check_call_host); + if (cancel_error != GRPC_ERROR_NONE) { + grpc_transport_stream_op_batch_finish_with_failure(exec_ctx, batch, + cancel_error); + } else { + char *call_host = grpc_slice_to_c_string(calld->host); + batch->handler_private.extra_arg = elem; + grpc_error *error = GRPC_ERROR_NONE; + if (grpc_channel_security_connector_check_call_host( + exec_ctx, chand->security_connector, call_host, + chand->auth_context, + GRPC_CLOSURE_INIT(&calld->closure, on_host_checked, batch, + grpc_schedule_on_exec_ctx), + &error)) { + // Synchronous return; invoke on_host_checked() directly. + on_host_checked(exec_ctx, batch, error); + GRPC_ERROR_UNREF(error); + } + gpr_free(call_host); + } GPR_TIMER_END("auth_start_transport_stream_op_batch", 0); return; /* early exit */ } @@ -315,6 +417,7 @@ static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, const grpc_call_final_info *final_info, grpc_closure *ignored) { call_data *calld = elem->call_data; + grpc_credentials_mdelem_array_destroy(exec_ctx, &calld->md_array); grpc_call_credentials_unref(exec_ctx, calld->creds); if (calld->have_host) { grpc_slice_unref_internal(exec_ctx, calld->host); @@ -324,6 +427,11 @@ static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, } reset_auth_metadata_context(&calld->auth_md_context); gpr_mu_destroy(&calld->security_context_mu); + gpr_atm cancel_state = gpr_atm_acq_load(&calld->cancellation_state); + grpc_error *cancel_error = GRPC_ERROR_NONE; + grpc_closure *cancel_func = NULL; + decode_cancel_state(cancel_state, &cancel_func, &cancel_error); + GRPC_ERROR_UNREF(cancel_error); } /* Constructor for channel_data */ diff --git a/src/core/lib/security/transport/security_connector.c b/src/core/lib/security/transport/security_connector.c index 6788126769a..a7568b995f5 100644 --- a/src/core/lib/security/transport/security_connector.c +++ b/src/core/lib/security/transport/security_connector.c @@ -136,15 +136,27 @@ void grpc_security_connector_check_peer(grpc_exec_ctx *exec_ctx, } } -void grpc_channel_security_connector_check_call_host( +bool grpc_channel_security_connector_check_call_host( grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc, const char *host, grpc_auth_context *auth_context, - grpc_security_call_host_check_cb cb, void *user_data) { + grpc_closure *on_call_host_checked, grpc_error **error) { if (sc == NULL || sc->check_call_host == NULL) { - cb(exec_ctx, user_data, GRPC_SECURITY_ERROR); - } else { - sc->check_call_host(exec_ctx, sc, host, auth_context, cb, user_data); + *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "cannot check call host -- no security connector"); + return true; } + return sc->check_call_host(exec_ctx, sc, host, auth_context, + on_call_host_checked, error); +} + +void grpc_channel_security_connector_cancel_check_call_host( + grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc, + grpc_closure *on_call_host_checked, grpc_error *error) { + if (sc == NULL || sc->cancel_check_call_host == NULL) { + GRPC_ERROR_UNREF(error); + return; + } + sc->cancel_check_call_host(exec_ctx, sc, on_call_host_checked, error); } #ifndef NDEBUG @@ -368,13 +380,19 @@ static void fake_server_check_peer(grpc_exec_ctx *exec_ctx, fake_check_peer(exec_ctx, sc, peer, auth_context, on_peer_checked); } -static void fake_channel_check_call_host(grpc_exec_ctx *exec_ctx, +static bool fake_channel_check_call_host(grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc, const char *host, grpc_auth_context *auth_context, - grpc_security_call_host_check_cb cb, - void *user_data) { - cb(exec_ctx, user_data, GRPC_SECURITY_OK); + grpc_closure *on_call_host_checked, + grpc_error **error) { + return true; +} + +static void fake_channel_cancel_check_call_host( + grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc, + grpc_closure *on_call_host_checked, grpc_error *error) { + GRPC_ERROR_UNREF(error); } static void fake_channel_add_handshakers( @@ -413,6 +431,7 @@ grpc_channel_security_connector *grpc_fake_channel_security_connector_create( c->base.request_metadata_creds = grpc_call_credentials_ref(request_metadata_creds); c->base.check_call_host = fake_channel_check_call_host; + c->base.cancel_check_call_host = fake_channel_cancel_check_call_host; c->base.add_handshakers = fake_channel_add_handshakers; c->target = gpr_strdup(target); const char *expected_targets = grpc_fake_transport_get_expected_targets(args); @@ -663,26 +682,35 @@ void tsi_shallow_peer_destruct(tsi_peer *peer) { if (peer->properties != NULL) gpr_free(peer->properties); } -static void ssl_channel_check_call_host(grpc_exec_ctx *exec_ctx, +static bool ssl_channel_check_call_host(grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc, const char *host, grpc_auth_context *auth_context, - grpc_security_call_host_check_cb cb, - void *user_data) { + grpc_closure *on_call_host_checked, + grpc_error **error) { grpc_ssl_channel_security_connector *c = (grpc_ssl_channel_security_connector *)sc; grpc_security_status status = GRPC_SECURITY_ERROR; tsi_peer peer = tsi_shallow_peer_from_ssl_auth_context(auth_context); if (ssl_host_matches_name(&peer, host)) status = GRPC_SECURITY_OK; - /* If the target name was overridden, then the original target_name was 'checked' transitively during the previous peer check at the end of the handshake. */ if (c->overridden_target_name != NULL && strcmp(host, c->target_name) == 0) { status = GRPC_SECURITY_OK; } - cb(exec_ctx, user_data, status); + if (status != GRPC_SECURITY_OK) { + *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "call host does not match SSL server name"); + } tsi_shallow_peer_destruct(&peer); + return true; +} + +static void ssl_channel_cancel_check_call_host( + grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc, + grpc_closure *on_call_host_checked, grpc_error *error) { + GRPC_ERROR_UNREF(error); } static grpc_security_connector_vtable ssl_channel_vtable = { @@ -811,6 +839,7 @@ grpc_security_status grpc_ssl_channel_security_connector_create( c->base.request_metadata_creds = grpc_call_credentials_ref(request_metadata_creds); c->base.check_call_host = ssl_channel_check_call_host; + c->base.cancel_check_call_host = ssl_channel_cancel_check_call_host; c->base.add_handshakers = ssl_channel_add_handshakers; gpr_split_host_port(target_name, &c->target_name, &port); gpr_free(port); diff --git a/src/core/lib/security/transport/security_connector.h b/src/core/lib/security/transport/security_connector.h index 1c0fe40045d..4f9b63ad202 100644 --- a/src/core/lib/security/transport/security_connector.h +++ b/src/core/lib/security/transport/security_connector.h @@ -117,27 +117,38 @@ grpc_security_connector *grpc_security_connector_find_in_args( typedef struct grpc_channel_security_connector grpc_channel_security_connector; -typedef void (*grpc_security_call_host_check_cb)(grpc_exec_ctx *exec_ctx, - void *user_data, - grpc_security_status status); - struct grpc_channel_security_connector { grpc_security_connector base; grpc_call_credentials *request_metadata_creds; - void (*check_call_host)(grpc_exec_ctx *exec_ctx, + bool (*check_call_host)(grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc, const char *host, grpc_auth_context *auth_context, - grpc_security_call_host_check_cb cb, void *user_data); + grpc_closure *on_call_host_checked, + grpc_error **error); + void (*cancel_check_call_host)(grpc_exec_ctx *exec_ctx, + grpc_channel_security_connector *sc, + grpc_closure *on_call_host_checked, + grpc_error *error); void (*add_handshakers)(grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc, grpc_handshake_manager *handshake_mgr); }; -/* Checks that the host that will be set for a call is acceptable. */ -void grpc_channel_security_connector_check_call_host( +/// Checks that the host that will be set for a call is acceptable. +/// Returns true if completed synchronously, in which case \a error will +/// be set to indicate the result. Otherwise, \a on_call_host_checked +/// will be invoked when complete. +bool grpc_channel_security_connector_check_call_host( grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc, const char *host, grpc_auth_context *auth_context, - grpc_security_call_host_check_cb cb, void *user_data); + grpc_closure *on_call_host_checked, grpc_error **error); + +/// Cancels a pending asychronous call to +/// grpc_channel_security_connector_check_call_host() with +/// \a on_call_host_checked as its callback. +void grpc_channel_security_connector_cancel_check_call_host( + grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc, + grpc_closure *on_call_host_checked, grpc_error *error); /* Registers handshakers with \a handshake_mgr. */ void grpc_channel_security_connector_add_handshakers( diff --git a/src/node/test/credentials_test.js b/src/node/test/credentials_test.js index 3688f03512f..0ff838e7d05 100644 --- a/src/node/test/credentials_test.js +++ b/src/node/test/credentials_test.js @@ -319,7 +319,9 @@ describe('client credentials', function() { client_options); client.unary({}, function(err, data) { assert(err); - assert.strictEqual(err.message, 'Authentication error'); + assert.strictEqual(err.message, + 'Getting metadata from plugin failed with error: ' + + 'Authentication error'); assert.strictEqual(err.code, grpc.status.UNAUTHENTICATED); done(); }); @@ -367,7 +369,9 @@ describe('client credentials', function() { client_options); client.unary({}, function(err, data) { assert(err); - assert.strictEqual(err.message, 'Authentication failure'); + assert.strictEqual(err.message, + 'Getting metadata from plugin failed with error: ' + + 'Authentication failure'); done(); }); }); diff --git a/test/core/end2end/fixtures/h2_oauth2.c b/test/core/end2end/fixtures/h2_oauth2.c index 9cbaaa08117..ee1d0b14169 100644 --- a/test/core/end2end/fixtures/h2_oauth2.c +++ b/test/core/end2end/fixtures/h2_oauth2.c @@ -137,10 +137,11 @@ void chttp2_tear_down_secure_fullstack(grpc_end2end_test_fixture *f) { static void chttp2_init_client_simple_ssl_with_oauth2_secure_fullstack( grpc_end2end_test_fixture *f, grpc_channel_args *client_args) { + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_channel_credentials *ssl_creds = grpc_ssl_credentials_create(test_root_cert, NULL, NULL); - grpc_call_credentials *oauth2_creds = - grpc_md_only_test_credentials_create("authorization", oauth2_md, 1); + grpc_call_credentials *oauth2_creds = grpc_md_only_test_credentials_create( + &exec_ctx, "authorization", oauth2_md, true /* is_async */); grpc_channel_credentials *ssl_oauth2_creds = grpc_composite_channel_credentials_create(ssl_creds, oauth2_creds, NULL); grpc_arg ssl_name_override = {GRPC_ARG_STRING, @@ -149,13 +150,10 @@ static void chttp2_init_client_simple_ssl_with_oauth2_secure_fullstack( grpc_channel_args *new_client_args = grpc_channel_args_copy_and_add(client_args, &ssl_name_override, 1); chttp2_init_client_secure_fullstack(f, new_client_args, ssl_oauth2_creds); - { - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - grpc_channel_args_destroy(&exec_ctx, new_client_args); - grpc_exec_ctx_finish(&exec_ctx); - } + grpc_channel_args_destroy(&exec_ctx, new_client_args); grpc_channel_credentials_release(ssl_creds); grpc_call_credentials_release(oauth2_creds); + grpc_exec_ctx_finish(&exec_ctx); } static int fail_server_auth_check(grpc_channel_args *server_args) { diff --git a/test/core/security/credentials_test.c b/test/core/security/credentials_test.c index a76cb0499d8..e60e398767e 100644 --- a/test/core/security/credentials_test.c +++ b/test/core/security/credentials_test.c @@ -105,8 +105,6 @@ static const char valid_oauth2_json_response[] = " \"expires_in\":3599, " " \"token_type\":\"Bearer\"}"; -static const char test_user_data[] = "user data"; - static const char test_scope[] = "perm1 perm2"; static const char test_signed_jwt[] = @@ -134,11 +132,6 @@ static char *test_json_key_str(void) { return result; } -typedef struct { - const char *key; - const char *value; -} expected_md; - static grpc_httpcli_response http_response(int status, const char *body) { grpc_httpcli_response response; memset(&response, 0, sizeof(grpc_httpcli_response)); @@ -150,89 +143,57 @@ static grpc_httpcli_response http_response(int status, const char *body) { /* -- Tests. -- */ -static void test_empty_md_store(void) { - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - grpc_credentials_md_store *store = grpc_credentials_md_store_create(0); - GPR_ASSERT(store->num_entries == 0); - GPR_ASSERT(store->allocated == 0); - grpc_credentials_md_store_unref(&exec_ctx, store); - grpc_exec_ctx_finish(&exec_ctx); -} - -static void test_ref_unref_empty_md_store(void) { - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - grpc_credentials_md_store *store = grpc_credentials_md_store_create(0); - grpc_credentials_md_store_ref(store); - grpc_credentials_md_store_ref(store); - GPR_ASSERT(store->num_entries == 0); - GPR_ASSERT(store->allocated == 0); - grpc_credentials_md_store_unref(&exec_ctx, store); - grpc_credentials_md_store_unref(&exec_ctx, store); - grpc_credentials_md_store_unref(&exec_ctx, store); - grpc_exec_ctx_finish(&exec_ctx); -} - -static void test_add_to_empty_md_store(void) { +static void test_empty_md_array(void) { grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - grpc_credentials_md_store *store = grpc_credentials_md_store_create(0); - const char *key_str = "hello"; - const char *value_str = "there blah blah blah blah blah blah blah"; - grpc_slice key = grpc_slice_from_copied_string(key_str); - grpc_slice value = grpc_slice_from_copied_string(value_str); - grpc_credentials_md_store_add(store, key, value); - GPR_ASSERT(store->num_entries == 1); - GPR_ASSERT(grpc_slice_eq(key, store->entries[0].key)); - GPR_ASSERT(grpc_slice_eq(value, store->entries[0].value)); - grpc_slice_unref(key); - grpc_slice_unref(value); - grpc_credentials_md_store_unref(&exec_ctx, store); + grpc_credentials_mdelem_array md_array; + memset(&md_array, 0, sizeof(md_array)); + GPR_ASSERT(md_array.md == NULL); + GPR_ASSERT(md_array.size == 0); + grpc_credentials_mdelem_array_destroy(&exec_ctx, &md_array); grpc_exec_ctx_finish(&exec_ctx); } -static void test_add_cstrings_to_empty_md_store(void) { +static void test_add_to_empty_md_array(void) { grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - grpc_credentials_md_store *store = grpc_credentials_md_store_create(0); - const char *key_str = "hello"; - const char *value_str = "there blah blah blah blah blah blah blah"; - grpc_credentials_md_store_add_cstrings(store, key_str, value_str); - GPR_ASSERT(store->num_entries == 1); - GPR_ASSERT(grpc_slice_str_cmp(store->entries[0].key, key_str) == 0); - GPR_ASSERT(grpc_slice_str_cmp(store->entries[0].value, value_str) == 0); - grpc_credentials_md_store_unref(&exec_ctx, store); + grpc_credentials_mdelem_array md_array; + memset(&md_array, 0, sizeof(md_array)); + const char *key = "hello"; + const char *value = "there blah blah blah blah blah blah blah"; + grpc_mdelem md = + grpc_mdelem_from_slices(&exec_ctx, grpc_slice_from_copied_string(key), + grpc_slice_from_copied_string(value)); + grpc_credentials_mdelem_array_add(&md_array, md); + GPR_ASSERT(md_array.size == 1); + GPR_ASSERT(grpc_mdelem_eq(md, md_array.md[0])); + GRPC_MDELEM_UNREF(&exec_ctx, md); + grpc_credentials_mdelem_array_destroy(&exec_ctx, &md_array); grpc_exec_ctx_finish(&exec_ctx); } -static void test_empty_preallocated_md_store(void) { +static void test_add_abunch_to_md_array(void) { grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - grpc_credentials_md_store *store = grpc_credentials_md_store_create(4); - GPR_ASSERT(store->num_entries == 0); - GPR_ASSERT(store->allocated == 4); - GPR_ASSERT(store->entries != NULL); - grpc_credentials_md_store_unref(&exec_ctx, store); - grpc_exec_ctx_finish(&exec_ctx); -} - -static void test_add_abunch_to_md_store(void) { - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - grpc_credentials_md_store *store = grpc_credentials_md_store_create(4); + grpc_credentials_mdelem_array md_array; + memset(&md_array, 0, sizeof(md_array)); + const char *key = "hello"; + const char *value = "there blah blah blah blah blah blah blah"; + grpc_mdelem md = + grpc_mdelem_from_slices(&exec_ctx, grpc_slice_from_copied_string(key), + grpc_slice_from_copied_string(value)); size_t num_entries = 1000; - const char *key_str = "hello"; - const char *value_str = "there blah blah blah blah blah blah blah"; - size_t i; - for (i = 0; i < num_entries; i++) { - grpc_credentials_md_store_add_cstrings(store, key_str, value_str); + for (size_t i = 0; i < num_entries; ++i) { + grpc_credentials_mdelem_array_add(&md_array, md); } - for (i = 0; i < num_entries; i++) { - GPR_ASSERT(grpc_slice_str_cmp(store->entries[i].key, key_str) == 0); - GPR_ASSERT(grpc_slice_str_cmp(store->entries[i].value, value_str) == 0); + for (size_t i = 0; i < num_entries; ++i) { + GPR_ASSERT(grpc_mdelem_eq(md_array.md[i], md)); } - grpc_credentials_md_store_unref(&exec_ctx, store); + GRPC_MDELEM_UNREF(&exec_ctx, md); + grpc_credentials_mdelem_array_destroy(&exec_ctx, &md_array); grpc_exec_ctx_finish(&exec_ctx); } static void test_oauth2_token_fetcher_creds_parsing_ok(void) { grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - grpc_credentials_md_store *token_md = NULL; + grpc_mdelem token_md = GRPC_MDNULL; gpr_timespec token_lifetime; grpc_httpcli_response response = http_response(200, valid_oauth2_json_response); @@ -241,20 +202,18 @@ static void test_oauth2_token_fetcher_creds_parsing_ok(void) { GRPC_CREDENTIALS_OK); GPR_ASSERT(token_lifetime.tv_sec == 3599); GPR_ASSERT(token_lifetime.tv_nsec == 0); - GPR_ASSERT(token_md->num_entries == 1); - GPR_ASSERT(grpc_slice_str_cmp(token_md->entries[0].key, "authorization") == - 0); - GPR_ASSERT(grpc_slice_str_cmp(token_md->entries[0].value, + GPR_ASSERT(grpc_slice_str_cmp(GRPC_MDKEY(token_md), "authorization") == 0); + GPR_ASSERT(grpc_slice_str_cmp(GRPC_MDVALUE(token_md), "Bearer ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_") == 0); - grpc_credentials_md_store_unref(&exec_ctx, token_md); + GRPC_MDELEM_UNREF(&exec_ctx, token_md); grpc_http_response_destroy(&response); grpc_exec_ctx_finish(&exec_ctx); } static void test_oauth2_token_fetcher_creds_parsing_bad_http_status(void) { grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - grpc_credentials_md_store *token_md = NULL; + grpc_mdelem token_md = GRPC_MDNULL; gpr_timespec token_lifetime; grpc_httpcli_response response = http_response(401, valid_oauth2_json_response); @@ -267,7 +226,7 @@ static void test_oauth2_token_fetcher_creds_parsing_bad_http_status(void) { static void test_oauth2_token_fetcher_creds_parsing_empty_http_body(void) { grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - grpc_credentials_md_store *token_md = NULL; + grpc_mdelem token_md = GRPC_MDNULL; gpr_timespec token_lifetime; grpc_httpcli_response response = http_response(200, ""); GPR_ASSERT(grpc_oauth2_token_fetcher_credentials_parse_server_response( @@ -279,7 +238,7 @@ static void test_oauth2_token_fetcher_creds_parsing_empty_http_body(void) { static void test_oauth2_token_fetcher_creds_parsing_invalid_json(void) { grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - grpc_credentials_md_store *token_md = NULL; + grpc_mdelem token_md = GRPC_MDNULL; gpr_timespec token_lifetime; grpc_httpcli_response response = http_response(200, @@ -295,7 +254,7 @@ static void test_oauth2_token_fetcher_creds_parsing_invalid_json(void) { static void test_oauth2_token_fetcher_creds_parsing_missing_token(void) { grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - grpc_credentials_md_store *token_md = NULL; + grpc_mdelem token_md = GRPC_MDNULL; gpr_timespec token_lifetime; grpc_httpcli_response response = http_response(200, "{" @@ -310,7 +269,7 @@ static void test_oauth2_token_fetcher_creds_parsing_missing_token(void) { static void test_oauth2_token_fetcher_creds_parsing_missing_token_type(void) { grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - grpc_credentials_md_store *token_md = NULL; + grpc_mdelem token_md = GRPC_MDNULL; gpr_timespec token_lifetime; grpc_httpcli_response response = http_response(200, @@ -327,7 +286,7 @@ static void test_oauth2_token_fetcher_creds_parsing_missing_token_type(void) { static void test_oauth2_token_fetcher_creds_parsing_missing_token_lifetime( void) { grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - grpc_credentials_md_store *token_md = NULL; + grpc_mdelem token_md = GRPC_MDNULL; gpr_timespec token_lifetime; grpc_httpcli_response response = http_response(200, @@ -340,75 +299,121 @@ static void test_oauth2_token_fetcher_creds_parsing_missing_token_lifetime( grpc_exec_ctx_finish(&exec_ctx); } -static void check_metadata(expected_md *expected, grpc_credentials_md *md_elems, - size_t num_md) { - size_t i; - for (i = 0; i < num_md; i++) { +typedef struct { + const char *key; + const char *value; +} expected_md; + +typedef struct { + grpc_error *expected_error; + const expected_md *expected; + size_t expected_size; + grpc_credentials_mdelem_array md_array; + grpc_closure on_request_metadata; + grpc_call_credentials *creds; +} request_metadata_state; + +static void check_metadata(const expected_md *expected, + grpc_credentials_mdelem_array *md_array) { + for (size_t i = 0; i < md_array->size; ++i) { size_t j; - for (j = 0; j < num_md; j++) { - if (0 == grpc_slice_str_cmp(md_elems[j].key, expected[i].key)) { - GPR_ASSERT(grpc_slice_str_cmp(md_elems[j].value, expected[i].value) == - 0); + for (j = 0; j < md_array->size; ++j) { + if (0 == + grpc_slice_str_cmp(GRPC_MDKEY(md_array->md[j]), expected[i].key)) { + GPR_ASSERT(grpc_slice_str_cmp(GRPC_MDVALUE(md_array->md[j]), + expected[i].value) == 0); break; } } - if (j == num_md) { + if (j == md_array->size) { gpr_log(GPR_ERROR, "key %s not found", expected[i].key); GPR_ASSERT(0); } } } -static void check_google_iam_metadata(grpc_exec_ctx *exec_ctx, void *user_data, - grpc_credentials_md *md_elems, - size_t num_md, - grpc_credentials_status status, - const char *error_details) { - grpc_call_credentials *c = (grpc_call_credentials *)user_data; - expected_md emd[] = {{GRPC_IAM_AUTHORIZATION_TOKEN_METADATA_KEY, - test_google_iam_authorization_token}, - {GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY, - test_google_iam_authority_selector}}; - GPR_ASSERT(status == GRPC_CREDENTIALS_OK); - GPR_ASSERT(error_details == NULL); - GPR_ASSERT(num_md == 2); - check_metadata(emd, md_elems, num_md); - grpc_call_credentials_unref(exec_ctx, c); +static void check_request_metadata(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + request_metadata_state *state = (request_metadata_state *)arg; + gpr_log(GPR_INFO, "expected_error: %s", + grpc_error_string(state->expected_error)); + gpr_log(GPR_INFO, "actual_error: %s", grpc_error_string(error)); + if (state->expected_error == GRPC_ERROR_NONE) { + GPR_ASSERT(error == GRPC_ERROR_NONE); + } else { + grpc_slice expected_error; + GPR_ASSERT(grpc_error_get_str(state->expected_error, + GRPC_ERROR_STR_DESCRIPTION, &expected_error)); + grpc_slice actual_error; + GPR_ASSERT( + grpc_error_get_str(error, GRPC_ERROR_STR_DESCRIPTION, &actual_error)); + GPR_ASSERT(grpc_slice_cmp(expected_error, actual_error) == 0); + GRPC_ERROR_UNREF(state->expected_error); + } + gpr_log(GPR_INFO, "expected_size=%" PRIdPTR " actual_size=%" PRIdPTR, + state->expected_size, state->md_array.size); + GPR_ASSERT(state->md_array.size == state->expected_size); + check_metadata(state->expected, &state->md_array); + grpc_credentials_mdelem_array_destroy(exec_ctx, &state->md_array); + gpr_free(state); +} + +static request_metadata_state *make_request_metadata_state( + grpc_error *expected_error, const expected_md *expected, + size_t expected_size) { + request_metadata_state *state = gpr_zalloc(sizeof(*state)); + state->expected_error = expected_error; + state->expected = expected; + state->expected_size = expected_size; + GRPC_CLOSURE_INIT(&state->on_request_metadata, check_request_metadata, state, + grpc_schedule_on_exec_ctx); + return state; +} + +static void run_request_metadata_test(grpc_exec_ctx *exec_ctx, + grpc_call_credentials *creds, + grpc_auth_metadata_context auth_md_ctx, + request_metadata_state *state) { + grpc_error *error = GRPC_ERROR_NONE; + if (grpc_call_credentials_get_request_metadata( + exec_ctx, creds, NULL, auth_md_ctx, &state->md_array, + &state->on_request_metadata, &error)) { + // Synchronous result. Invoke the callback directly. + check_request_metadata(exec_ctx, state, error); + GRPC_ERROR_UNREF(error); + } } static void test_google_iam_creds(void) { grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + expected_md emd[] = {{GRPC_IAM_AUTHORIZATION_TOKEN_METADATA_KEY, + test_google_iam_authorization_token}, + {GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY, + test_google_iam_authority_selector}}; + request_metadata_state *state = + make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd)); grpc_call_credentials *creds = grpc_google_iam_credentials_create( test_google_iam_authorization_token, test_google_iam_authority_selector, NULL); grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method, NULL, NULL}; - grpc_call_credentials_get_request_metadata( - &exec_ctx, creds, NULL, auth_md_ctx, check_google_iam_metadata, creds); + run_request_metadata_test(&exec_ctx, creds, auth_md_ctx, state); + grpc_call_credentials_unref(&exec_ctx, creds); grpc_exec_ctx_finish(&exec_ctx); } -static void check_access_token_metadata( - grpc_exec_ctx *exec_ctx, void *user_data, grpc_credentials_md *md_elems, - size_t num_md, grpc_credentials_status status, const char *error_details) { - grpc_call_credentials *c = (grpc_call_credentials *)user_data; - expected_md emd[] = {{GRPC_AUTHORIZATION_METADATA_KEY, "Bearer blah"}}; - GPR_ASSERT(status == GRPC_CREDENTIALS_OK); - GPR_ASSERT(error_details == NULL); - GPR_ASSERT(num_md == 1); - check_metadata(emd, md_elems, num_md); - grpc_call_credentials_unref(exec_ctx, c); -} - static void test_access_token_creds(void) { grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + expected_md emd[] = {{GRPC_AUTHORIZATION_METADATA_KEY, "Bearer blah"}}; + request_metadata_state *state = + make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd)); grpc_call_credentials *creds = grpc_access_token_credentials_create("blah", NULL); grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method, NULL, NULL}; GPR_ASSERT(strcmp(creds->type, GRPC_CALL_CREDENTIALS_TYPE_OAUTH2) == 0); - grpc_call_credentials_get_request_metadata( - &exec_ctx, creds, NULL, auth_md_ctx, check_access_token_metadata, creds); + run_request_metadata_test(&exec_ctx, creds, auth_md_ctx, state); + grpc_call_credentials_unref(&exec_ctx, creds); grpc_exec_ctx_finish(&exec_ctx); } @@ -444,30 +449,20 @@ static void test_channel_oauth2_composite_creds(void) { grpc_exec_ctx_finish(&exec_ctx); } -static void check_oauth2_google_iam_composite_metadata( - grpc_exec_ctx *exec_ctx, void *user_data, grpc_credentials_md *md_elems, - size_t num_md, grpc_credentials_status status, const char *error_details) { - grpc_call_credentials *c = (grpc_call_credentials *)user_data; +static void test_oauth2_google_iam_composite_creds(void) { + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; expected_md emd[] = { {GRPC_AUTHORIZATION_METADATA_KEY, test_oauth2_bearer_token}, {GRPC_IAM_AUTHORIZATION_TOKEN_METADATA_KEY, test_google_iam_authorization_token}, {GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY, test_google_iam_authority_selector}}; - GPR_ASSERT(status == GRPC_CREDENTIALS_OK); - GPR_ASSERT(error_details == NULL); - GPR_ASSERT(num_md == 3); - check_metadata(emd, md_elems, num_md); - grpc_call_credentials_unref(exec_ctx, c); -} - -static void test_oauth2_google_iam_composite_creds(void) { - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - const grpc_call_credentials_array *creds_array; + request_metadata_state *state = + make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd)); grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method, NULL, NULL}; grpc_call_credentials *oauth2_creds = grpc_md_only_test_credentials_create( - "authorization", test_oauth2_bearer_token, 0); + &exec_ctx, "authorization", test_oauth2_bearer_token, 0); grpc_call_credentials *google_iam_creds = grpc_google_iam_credentials_create( test_google_iam_authorization_token, test_google_iam_authority_selector, NULL); @@ -478,16 +473,15 @@ static void test_oauth2_google_iam_composite_creds(void) { grpc_call_credentials_unref(&exec_ctx, google_iam_creds); GPR_ASSERT( strcmp(composite_creds->type, GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0); - creds_array = + const grpc_call_credentials_array *creds_array = grpc_composite_call_credentials_get_credentials(composite_creds); GPR_ASSERT(creds_array->num_creds == 2); GPR_ASSERT(strcmp(creds_array->creds_array[0]->type, GRPC_CALL_CREDENTIALS_TYPE_OAUTH2) == 0); GPR_ASSERT(strcmp(creds_array->creds_array[1]->type, GRPC_CALL_CREDENTIALS_TYPE_IAM) == 0); - grpc_call_credentials_get_request_metadata( - &exec_ctx, composite_creds, NULL, auth_md_ctx, - check_oauth2_google_iam_composite_metadata, composite_creds); + run_request_metadata_test(&exec_ctx, composite_creds, auth_md_ctx, state); + grpc_call_credentials_unref(&exec_ctx, composite_creds); grpc_exec_ctx_finish(&exec_ctx); } @@ -541,29 +535,6 @@ static void test_channel_oauth2_google_iam_composite_creds(void) { grpc_exec_ctx_finish(&exec_ctx); } -static void on_oauth2_creds_get_metadata_success( - grpc_exec_ctx *exec_ctx, void *user_data, grpc_credentials_md *md_elems, - size_t num_md, grpc_credentials_status status, const char *error_details) { - GPR_ASSERT(status == GRPC_CREDENTIALS_OK); - GPR_ASSERT(error_details == NULL); - GPR_ASSERT(num_md == 1); - GPR_ASSERT(grpc_slice_str_cmp(md_elems[0].key, "authorization") == 0); - GPR_ASSERT(grpc_slice_str_cmp(md_elems[0].value, - "Bearer ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_") == - 0); - GPR_ASSERT(user_data != NULL); - GPR_ASSERT(strcmp((const char *)user_data, test_user_data) == 0); -} - -static void on_oauth2_creds_get_metadata_failure( - grpc_exec_ctx *exec_ctx, void *user_data, grpc_credentials_md *md_elems, - size_t num_md, grpc_credentials_status status, const char *error_details) { - GPR_ASSERT(status == GRPC_CREDENTIALS_ERROR); - GPR_ASSERT(num_md == 0); - GPR_ASSERT(user_data != NULL); - GPR_ASSERT(strcmp((const char *)user_data, test_user_data) == 0); -} - static void validate_compute_engine_http_request( const grpc_httpcli_request *request) { GPR_ASSERT(request->handshaker != &grpc_httpcli_ssl); @@ -616,43 +587,48 @@ static int httpcli_get_should_not_be_called(grpc_exec_ctx *exec_ctx, static void test_compute_engine_creds_success(void) { grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - grpc_call_credentials *compute_engine_creds = + expected_md emd[] = { + {"authorization", "Bearer ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_"}}; + grpc_call_credentials *creds = grpc_google_compute_engine_credentials_create(NULL); grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method, NULL, NULL}; /* First request: http get should be called. */ + request_metadata_state *state = + make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd)); grpc_httpcli_set_override(compute_engine_httpcli_get_success_override, httpcli_post_should_not_be_called); - grpc_call_credentials_get_request_metadata( - &exec_ctx, compute_engine_creds, NULL, auth_md_ctx, - on_oauth2_creds_get_metadata_success, (void *)test_user_data); + run_request_metadata_test(&exec_ctx, creds, auth_md_ctx, state); grpc_exec_ctx_flush(&exec_ctx); /* Second request: the cached token should be served directly. */ + state = + make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd)); grpc_httpcli_set_override(httpcli_get_should_not_be_called, httpcli_post_should_not_be_called); - grpc_call_credentials_get_request_metadata( - &exec_ctx, compute_engine_creds, NULL, auth_md_ctx, - on_oauth2_creds_get_metadata_success, (void *)test_user_data); - grpc_exec_ctx_finish(&exec_ctx); + run_request_metadata_test(&exec_ctx, creds, auth_md_ctx, state); + grpc_exec_ctx_flush(&exec_ctx); - grpc_call_credentials_unref(&exec_ctx, compute_engine_creds); + grpc_call_credentials_unref(&exec_ctx, creds); grpc_httpcli_set_override(NULL, NULL); + grpc_exec_ctx_finish(&exec_ctx); } static void test_compute_engine_creds_failure(void) { grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + request_metadata_state *state = make_request_metadata_state( + GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Error occured when fetching oauth2 token."), + NULL, 0); grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method, NULL, NULL}; - grpc_call_credentials *compute_engine_creds = + grpc_call_credentials *creds = grpc_google_compute_engine_credentials_create(NULL); grpc_httpcli_set_override(compute_engine_httpcli_get_failure_override, httpcli_post_should_not_be_called); - grpc_call_credentials_get_request_metadata( - &exec_ctx, compute_engine_creds, NULL, auth_md_ctx, - on_oauth2_creds_get_metadata_failure, (void *)test_user_data); - grpc_call_credentials_unref(&exec_ctx, compute_engine_creds); + run_request_metadata_test(&exec_ctx, creds, auth_md_ctx, state); + grpc_call_credentials_unref(&exec_ctx, creds); grpc_httpcli_set_override(NULL, NULL); grpc_exec_ctx_finish(&exec_ctx); } @@ -702,46 +678,48 @@ static int refresh_token_httpcli_post_failure( static void test_refresh_token_creds_success(void) { grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + expected_md emd[] = { + {"authorization", "Bearer ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_"}}; grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method, NULL, NULL}; - grpc_call_credentials *refresh_token_creds = - grpc_google_refresh_token_credentials_create(test_refresh_token_str, - NULL); + grpc_call_credentials *creds = grpc_google_refresh_token_credentials_create( + test_refresh_token_str, NULL); /* First request: http get should be called. */ + request_metadata_state *state = + make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd)); grpc_httpcli_set_override(httpcli_get_should_not_be_called, refresh_token_httpcli_post_success); - grpc_call_credentials_get_request_metadata( - &exec_ctx, refresh_token_creds, NULL, auth_md_ctx, - on_oauth2_creds_get_metadata_success, (void *)test_user_data); + run_request_metadata_test(&exec_ctx, creds, auth_md_ctx, state); grpc_exec_ctx_flush(&exec_ctx); /* Second request: the cached token should be served directly. */ + state = + make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd)); grpc_httpcli_set_override(httpcli_get_should_not_be_called, httpcli_post_should_not_be_called); - grpc_call_credentials_get_request_metadata( - &exec_ctx, refresh_token_creds, NULL, auth_md_ctx, - on_oauth2_creds_get_metadata_success, (void *)test_user_data); + run_request_metadata_test(&exec_ctx, creds, auth_md_ctx, state); grpc_exec_ctx_flush(&exec_ctx); - grpc_call_credentials_unref(&exec_ctx, refresh_token_creds); + grpc_call_credentials_unref(&exec_ctx, creds); grpc_httpcli_set_override(NULL, NULL); grpc_exec_ctx_finish(&exec_ctx); } static void test_refresh_token_creds_failure(void) { grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + request_metadata_state *state = make_request_metadata_state( + GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Error occured when fetching oauth2 token."), + NULL, 0); grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method, NULL, NULL}; - grpc_call_credentials *refresh_token_creds = - grpc_google_refresh_token_credentials_create(test_refresh_token_str, - NULL); + grpc_call_credentials *creds = grpc_google_refresh_token_credentials_create( + test_refresh_token_str, NULL); grpc_httpcli_set_override(httpcli_get_should_not_be_called, refresh_token_httpcli_post_failure); - grpc_call_credentials_get_request_metadata( - &exec_ctx, refresh_token_creds, NULL, auth_md_ctx, - on_oauth2_creds_get_metadata_failure, (void *)test_user_data); - grpc_call_credentials_unref(&exec_ctx, refresh_token_creds); + run_request_metadata_test(&exec_ctx, creds, auth_md_ctx, state); + grpc_call_credentials_unref(&exec_ctx, creds); grpc_httpcli_set_override(NULL, NULL); grpc_exec_ctx_finish(&exec_ctx); } @@ -792,30 +770,6 @@ static char *encode_and_sign_jwt_should_not_be_called( return NULL; } -static void on_jwt_creds_get_metadata_success( - grpc_exec_ctx *exec_ctx, void *user_data, grpc_credentials_md *md_elems, - size_t num_md, grpc_credentials_status status, const char *error_details) { - char *expected_md_value; - gpr_asprintf(&expected_md_value, "Bearer %s", test_signed_jwt); - GPR_ASSERT(status == GRPC_CREDENTIALS_OK); - GPR_ASSERT(error_details == NULL); - GPR_ASSERT(num_md == 1); - GPR_ASSERT(grpc_slice_str_cmp(md_elems[0].key, "authorization") == 0); - GPR_ASSERT(grpc_slice_str_cmp(md_elems[0].value, expected_md_value) == 0); - GPR_ASSERT(user_data != NULL); - GPR_ASSERT(strcmp((const char *)user_data, test_user_data) == 0); - gpr_free(expected_md_value); -} - -static void on_jwt_creds_get_metadata_failure( - grpc_exec_ctx *exec_ctx, void *user_data, grpc_credentials_md *md_elems, - size_t num_md, grpc_credentials_status status, const char *error_details) { - GPR_ASSERT(status == GRPC_CREDENTIALS_ERROR); - GPR_ASSERT(num_md == 0); - GPR_ASSERT(user_data != NULL); - GPR_ASSERT(strcmp((const char *)user_data, test_user_data) == 0); -} - static grpc_service_account_jwt_access_credentials *creds_as_jwt( grpc_call_credentials *creds) { GPR_ASSERT(creds != NULL); @@ -860,37 +814,42 @@ static void test_jwt_creds_success(void) { grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method, NULL, NULL}; - grpc_call_credentials *jwt_creds = + char *expected_md_value; + gpr_asprintf(&expected_md_value, "Bearer %s", test_signed_jwt); + expected_md emd[] = {{"authorization", expected_md_value}}; + grpc_call_credentials *creds = grpc_service_account_jwt_access_credentials_create( json_key_string, grpc_max_auth_token_lifetime(), NULL); /* First request: jwt_encode_and_sign should be called. */ + request_metadata_state *state = + make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd)); grpc_jwt_encode_and_sign_set_override(encode_and_sign_jwt_success); - grpc_call_credentials_get_request_metadata( - &exec_ctx, jwt_creds, NULL, auth_md_ctx, - on_jwt_creds_get_metadata_success, (void *)test_user_data); + run_request_metadata_test(&exec_ctx, creds, auth_md_ctx, state); grpc_exec_ctx_flush(&exec_ctx); /* Second request: the cached token should be served directly. */ + state = + make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd)); grpc_jwt_encode_and_sign_set_override( encode_and_sign_jwt_should_not_be_called); - grpc_call_credentials_get_request_metadata( - &exec_ctx, jwt_creds, NULL, auth_md_ctx, - on_jwt_creds_get_metadata_success, (void *)test_user_data); + run_request_metadata_test(&exec_ctx, creds, auth_md_ctx, state); grpc_exec_ctx_flush(&exec_ctx); /* Third request: Different service url so jwt_encode_and_sign should be called again (no caching). */ + state = + make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd)); auth_md_ctx.service_url = other_test_service_url; grpc_jwt_encode_and_sign_set_override(encode_and_sign_jwt_success); - grpc_call_credentials_get_request_metadata( - &exec_ctx, jwt_creds, NULL, auth_md_ctx, - on_jwt_creds_get_metadata_success, (void *)test_user_data); + run_request_metadata_test(&exec_ctx, creds, auth_md_ctx, state); grpc_exec_ctx_flush(&exec_ctx); + grpc_call_credentials_unref(&exec_ctx, creds); gpr_free(json_key_string); - grpc_call_credentials_unref(&exec_ctx, jwt_creds); + gpr_free(expected_md_value); grpc_jwt_encode_and_sign_set_override(NULL); + grpc_exec_ctx_finish(&exec_ctx); } static void test_jwt_creds_signing_failure(void) { @@ -898,17 +857,17 @@ static void test_jwt_creds_signing_failure(void) { grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method, NULL, NULL}; - grpc_call_credentials *jwt_creds = + request_metadata_state *state = make_request_metadata_state( + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Could not generate JWT."), NULL, 0); + grpc_call_credentials *creds = grpc_service_account_jwt_access_credentials_create( json_key_string, grpc_max_auth_token_lifetime(), NULL); grpc_jwt_encode_and_sign_set_override(encode_and_sign_jwt_failure); - grpc_call_credentials_get_request_metadata( - &exec_ctx, jwt_creds, NULL, auth_md_ctx, - on_jwt_creds_get_metadata_failure, (void *)test_user_data); + run_request_metadata_test(&exec_ctx, creds, auth_md_ctx, state); gpr_free(json_key_string); - grpc_call_credentials_unref(&exec_ctx, jwt_creds); + grpc_call_credentials_unref(&exec_ctx, creds); grpc_jwt_encode_and_sign_set_override(NULL); grpc_exec_ctx_finish(&exec_ctx); } @@ -986,8 +945,10 @@ static char *null_well_known_creds_path_getter(void) { return NULL; } static void test_google_default_creds_gce(void) { grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - grpc_composite_channel_credentials *creds; - grpc_channel_credentials *cached_creds; + expected_md emd[] = { + {"authorization", "Bearer ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_"}}; + request_metadata_state *state = + make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd)); grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method, NULL, NULL}; grpc_flush_cached_google_default_credentials(); @@ -999,33 +960,33 @@ static void test_google_default_creds_gce(void) { grpc_httpcli_set_override( default_creds_gce_detection_httpcli_get_success_override, httpcli_post_should_not_be_called); - creds = (grpc_composite_channel_credentials *) - grpc_google_default_credentials_create(); + grpc_composite_channel_credentials *creds = + (grpc_composite_channel_credentials *) + grpc_google_default_credentials_create(); /* Verify that the default creds actually embeds a GCE creds. */ GPR_ASSERT(creds != NULL); GPR_ASSERT(creds->call_creds != NULL); grpc_httpcli_set_override(compute_engine_httpcli_get_success_override, httpcli_post_should_not_be_called); - grpc_call_credentials_get_request_metadata( - &exec_ctx, creds->call_creds, NULL, auth_md_ctx, - on_oauth2_creds_get_metadata_success, (void *)test_user_data); + run_request_metadata_test(&exec_ctx, creds->call_creds, auth_md_ctx, state); grpc_exec_ctx_flush(&exec_ctx); - grpc_exec_ctx_finish(&exec_ctx); /* Check that we get a cached creds if we call grpc_google_default_credentials_create again. GCE detection should not occur anymore either. */ grpc_httpcli_set_override(httpcli_get_should_not_be_called, httpcli_post_should_not_be_called); - cached_creds = grpc_google_default_credentials_create(); + grpc_channel_credentials *cached_creds = + grpc_google_default_credentials_create(); GPR_ASSERT(cached_creds == &creds->base); /* Cleanup. */ - grpc_channel_credentials_release(cached_creds); - grpc_channel_credentials_release(&creds->base); + grpc_channel_credentials_unref(&exec_ctx, cached_creds); + grpc_channel_credentials_unref(&exec_ctx, &creds->base); grpc_httpcli_set_override(NULL, NULL); grpc_override_well_known_credentials_path_getter(NULL); + grpc_exec_ctx_finish(&exec_ctx); } static int default_creds_gce_detection_httpcli_get_failure_override( @@ -1068,12 +1029,7 @@ typedef enum { PLUGIN_DESTROY_CALLED_STATE } plugin_state; -typedef struct { - const char *key; - const char *value; -} plugin_metadata; - -static const plugin_metadata plugin_md[] = {{"foo", "bar"}, {"hi", "there"}}; +static const expected_md plugin_md[] = {{"foo", "bar"}, {"hi", "there"}}; static void plugin_get_metadata_success(void *state, grpc_auth_metadata_context context, @@ -1110,79 +1066,60 @@ static void plugin_get_metadata_failure(void *state, cb(user_data, NULL, 0, GRPC_STATUS_UNAUTHENTICATED, plugin_error_details); } -static void on_plugin_metadata_received_success( - grpc_exec_ctx *exec_ctx, void *user_data, grpc_credentials_md *md_elems, - size_t num_md, grpc_credentials_status status, const char *error_details) { - size_t i = 0; - GPR_ASSERT(user_data == NULL); - GPR_ASSERT(md_elems != NULL); - GPR_ASSERT(num_md == GPR_ARRAY_SIZE(plugin_md)); - for (i = 0; i < num_md; i++) { - GPR_ASSERT(grpc_slice_str_cmp(md_elems[i].key, plugin_md[i].key) == 0); - GPR_ASSERT(grpc_slice_str_cmp(md_elems[i].value, plugin_md[i].value) == 0); - } -} - -static void on_plugin_metadata_received_failure( - grpc_exec_ctx *exec_ctx, void *user_data, grpc_credentials_md *md_elems, - size_t num_md, grpc_credentials_status status, const char *error_details) { - GPR_ASSERT(user_data == NULL); - GPR_ASSERT(md_elems == NULL); - GPR_ASSERT(num_md == 0); - GPR_ASSERT(status == GRPC_CREDENTIALS_ERROR); - GPR_ASSERT(error_details != NULL); - GPR_ASSERT(strcmp(error_details, plugin_error_details) == 0); -} - static void plugin_destroy(void *state) { plugin_state *s = (plugin_state *)state; *s = PLUGIN_DESTROY_CALLED_STATE; } static void test_metadata_plugin_success(void) { - grpc_call_credentials *creds; plugin_state state = PLUGIN_INITIAL_STATE; grpc_metadata_credentials_plugin plugin; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method, NULL, NULL}; + request_metadata_state *md_state = make_request_metadata_state( + GRPC_ERROR_NONE, plugin_md, GPR_ARRAY_SIZE(plugin_md)); plugin.state = &state; plugin.get_metadata = plugin_get_metadata_success; plugin.destroy = plugin_destroy; - creds = grpc_metadata_credentials_create_from_plugin(plugin, NULL); + grpc_call_credentials *creds = + grpc_metadata_credentials_create_from_plugin(plugin, NULL); GPR_ASSERT(state == PLUGIN_INITIAL_STATE); - grpc_call_credentials_get_request_metadata( - &exec_ctx, creds, NULL, auth_md_ctx, on_plugin_metadata_received_success, - NULL); + run_request_metadata_test(&exec_ctx, creds, auth_md_ctx, md_state); GPR_ASSERT(state == PLUGIN_GET_METADATA_CALLED_STATE); - grpc_call_credentials_release(creds); - GPR_ASSERT(state == PLUGIN_DESTROY_CALLED_STATE); + grpc_call_credentials_unref(&exec_ctx, creds); grpc_exec_ctx_finish(&exec_ctx); + GPR_ASSERT(state == PLUGIN_DESTROY_CALLED_STATE); } static void test_metadata_plugin_failure(void) { - grpc_call_credentials *creds; plugin_state state = PLUGIN_INITIAL_STATE; grpc_metadata_credentials_plugin plugin; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method, NULL, NULL}; + char *expected_error; + gpr_asprintf(&expected_error, + "Getting metadata from plugin failed with error: %s", + plugin_error_details); + request_metadata_state *md_state = make_request_metadata_state( + GRPC_ERROR_CREATE_FROM_COPIED_STRING(expected_error), NULL, 0); + gpr_free(expected_error); plugin.state = &state; plugin.get_metadata = plugin_get_metadata_failure; plugin.destroy = plugin_destroy; - creds = grpc_metadata_credentials_create_from_plugin(plugin, NULL); + grpc_call_credentials *creds = + grpc_metadata_credentials_create_from_plugin(plugin, NULL); GPR_ASSERT(state == PLUGIN_INITIAL_STATE); - grpc_call_credentials_get_request_metadata( - &exec_ctx, creds, NULL, auth_md_ctx, on_plugin_metadata_received_failure, - NULL); + run_request_metadata_test(&exec_ctx, creds, auth_md_ctx, md_state); GPR_ASSERT(state == PLUGIN_GET_METADATA_CALLED_STATE); - grpc_call_credentials_release(creds); - GPR_ASSERT(state == PLUGIN_DESTROY_CALLED_STATE); + grpc_call_credentials_unref(&exec_ctx, creds); grpc_exec_ctx_finish(&exec_ctx); + GPR_ASSERT(state == PLUGIN_DESTROY_CALLED_STATE); } static void test_get_well_known_google_credentials_file_path(void) { @@ -1233,12 +1170,9 @@ static void test_channel_creds_duplicate_without_call_creds(void) { int main(int argc, char **argv) { grpc_test_init(argc, argv); grpc_init(); - test_empty_md_store(); - test_ref_unref_empty_md_store(); - test_add_to_empty_md_store(); - test_add_cstrings_to_empty_md_store(); - test_empty_preallocated_md_store(); - test_add_abunch_to_md_store(); + test_empty_md_array(); + test_add_to_empty_md_array(); + test_add_abunch_to_md_array(); test_oauth2_token_fetcher_creds_parsing_ok(); test_oauth2_token_fetcher_creds_parsing_bad_http_status(); test_oauth2_token_fetcher_creds_parsing_empty_http_body(); diff --git a/test/core/security/oauth2_utils.c b/test/core/security/oauth2_utils.c index e2331fbd97c..fdbc6ea7417 100644 --- a/test/core/security/oauth2_utils.c +++ b/test/core/security/oauth2_utils.c @@ -32,29 +32,31 @@ typedef struct { gpr_mu *mu; grpc_polling_entity pops; - int is_done; + bool is_done; char *token; + + grpc_credentials_mdelem_array md_array; + grpc_closure closure; } oauth2_request; -static void on_oauth2_response(grpc_exec_ctx *exec_ctx, void *user_data, - grpc_credentials_md *md_elems, size_t num_md, - grpc_credentials_status status, - const char *error_details) { - oauth2_request *request = (oauth2_request *)user_data; +static void on_oauth2_response(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + oauth2_request *request = (oauth2_request *)arg; char *token = NULL; grpc_slice token_slice; - if (status == GRPC_CREDENTIALS_ERROR) { - gpr_log(GPR_ERROR, "Fetching token failed."); + if (error != GRPC_ERROR_NONE) { + gpr_log(GPR_ERROR, "Fetching token failed: %s", grpc_error_string(error)); } else { - GPR_ASSERT(num_md == 1); - token_slice = md_elems[0].value; + GPR_ASSERT(request->md_array.size == 1); + token_slice = GRPC_MDVALUE(request->md_array.md[0]); token = (char *)gpr_malloc(GRPC_SLICE_LENGTH(token_slice) + 1); memcpy(token, GRPC_SLICE_START_PTR(token_slice), GRPC_SLICE_LENGTH(token_slice)); token[GRPC_SLICE_LENGTH(token_slice)] = '\0'; } + grpc_credentials_mdelem_array_destroy(exec_ctx, &request->md_array); gpr_mu_lock(request->mu); - request->is_done = 1; + request->is_done = true; request->token = token; GRPC_LOG_IF_ERROR( "pollset_kick", @@ -68,6 +70,7 @@ static void do_nothing(grpc_exec_ctx *exec_ctx, void *unused, char *grpc_test_fetch_oauth2_token_with_credentials( grpc_call_credentials *creds) { oauth2_request request; + memset(&request, 0, sizeof(request)); grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_closure do_nothing_closure; grpc_auth_metadata_context null_ctx = {"", "", NULL, NULL}; @@ -75,15 +78,23 @@ char *grpc_test_fetch_oauth2_token_with_credentials( grpc_pollset *pollset = (grpc_pollset *)gpr_zalloc(grpc_pollset_size()); grpc_pollset_init(pollset, &request.mu); request.pops = grpc_polling_entity_create_from_pollset(pollset); - request.is_done = 0; + request.is_done = false; GRPC_CLOSURE_INIT(&do_nothing_closure, do_nothing, NULL, grpc_schedule_on_exec_ctx); - grpc_call_credentials_get_request_metadata( - &exec_ctx, creds, &request.pops, null_ctx, on_oauth2_response, &request); + GRPC_CLOSURE_INIT(&request.closure, on_oauth2_response, &request, + grpc_schedule_on_exec_ctx); - grpc_exec_ctx_finish(&exec_ctx); + grpc_error *error = GRPC_ERROR_NONE; + if (grpc_call_credentials_get_request_metadata( + &exec_ctx, creds, &request.pops, null_ctx, &request.md_array, + &request.closure, &error)) { + // Synchronous result; invoke callback directly. + on_oauth2_response(&exec_ctx, &request, error); + GRPC_ERROR_UNREF(error); + } + grpc_exec_ctx_flush(&exec_ctx); gpr_mu_lock(request.mu); while (!request.is_done) { @@ -94,7 +105,7 @@ char *grpc_test_fetch_oauth2_token_with_credentials( grpc_polling_entity_pollset(&request.pops), &worker, gpr_now(GPR_CLOCK_MONOTONIC), gpr_inf_future(GPR_CLOCK_MONOTONIC)))) { - request.is_done = 1; + request.is_done = true; } } gpr_mu_unlock(request.mu); diff --git a/test/core/security/print_google_default_creds_token.c b/test/core/security/print_google_default_creds_token.c index 3c3d3a7c105..e1385a80caa 100644 --- a/test/core/security/print_google_default_creds_token.c +++ b/test/core/security/print_google_default_creds_token.c @@ -35,25 +35,26 @@ typedef struct { gpr_mu *mu; grpc_polling_entity pops; - int is_done; + bool is_done; + + grpc_credentials_mdelem_array md_array; + grpc_closure on_request_metadata; } synchronizer; -static void on_metadata_response(grpc_exec_ctx *exec_ctx, void *user_data, - grpc_credentials_md *md_elems, size_t num_md, - grpc_credentials_status status, - const char *error_details) { - synchronizer *sync = user_data; - if (status == GRPC_CREDENTIALS_ERROR) { - fprintf(stderr, "Fetching token failed.\n"); +static void on_metadata_response(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + synchronizer *sync = arg; + if (error != GRPC_ERROR_NONE) { + fprintf(stderr, "Fetching token failed: %s\n", grpc_error_string(error)); } else { char *token; - GPR_ASSERT(num_md == 1); - token = grpc_slice_to_c_string(md_elems[0].value); + GPR_ASSERT(sync->md_array.size == 1); + token = grpc_slice_to_c_string(GRPC_MDVALUE(sync->md_array.md[0])); printf("\nGot token: %s\n\n", token); gpr_free(token); } gpr_mu_lock(sync->mu); - sync->is_done = 1; + sync->is_done = true; GRPC_LOG_IF_ERROR( "pollset_kick", grpc_pollset_kick(grpc_polling_entity_pollset(&sync->pops), NULL)); @@ -83,14 +84,23 @@ int main(int argc, char **argv) { goto end; } + memset(&sync, 0, sizeof(sync)); grpc_pollset *pollset = gpr_zalloc(grpc_pollset_size()); grpc_pollset_init(pollset, &sync.mu); sync.pops = grpc_polling_entity_create_from_pollset(pollset); - sync.is_done = 0; + sync.is_done = false; + GRPC_CLOSURE_INIT(&sync.on_request_metadata, on_metadata_response, &sync, + grpc_schedule_on_exec_ctx); - grpc_call_credentials_get_request_metadata( - &exec_ctx, ((grpc_composite_channel_credentials *)creds)->call_creds, - &sync.pops, context, on_metadata_response, &sync); + grpc_error *error = GRPC_ERROR_NONE; + if (grpc_call_credentials_get_request_metadata( + &exec_ctx, ((grpc_composite_channel_credentials *)creds)->call_creds, + &sync.pops, context, &sync.md_array, &sync.on_request_metadata, + &error)) { + // Synchronous response. Invoke callback directly. + on_metadata_response(&exec_ctx, &sync, error); + GRPC_ERROR_UNREF(error); + } gpr_mu_lock(sync.mu); while (!sync.is_done) { @@ -101,7 +111,7 @@ int main(int argc, char **argv) { grpc_polling_entity_pollset(&sync.pops), &worker, gpr_now(GPR_CLOCK_MONOTONIC), gpr_inf_future(GPR_CLOCK_MONOTONIC)))) - sync.is_done = 1; + sync.is_done = true; gpr_mu_unlock(sync.mu); grpc_exec_ctx_flush(&exec_ctx); gpr_mu_lock(sync.mu); diff --git a/test/cpp/end2end/end2end_test.cc b/test/cpp/end2end/end2end_test.cc index 8d12971bc1b..8bada48a2b1 100644 --- a/test/cpp/end2end/end2end_test.cc +++ b/test/cpp/end2end/end2end_test.cc @@ -1565,7 +1565,9 @@ TEST_P(SecureEnd2endTest, NonBlockingAuthMetadataPluginFailure) { Status s = stub_->Echo(&context, request, &response); EXPECT_FALSE(s.ok()); EXPECT_EQ(s.error_code(), StatusCode::UNAUTHENTICATED); - EXPECT_EQ(s.error_message(), kTestCredsPluginErrorMsg); + EXPECT_EQ(s.error_message(), + grpc::string("Getting metadata from plugin failed with error: ") + + kTestCredsPluginErrorMsg); } TEST_P(SecureEnd2endTest, NonBlockingAuthMetadataPluginAndProcessorSuccess) { @@ -1624,7 +1626,9 @@ TEST_P(SecureEnd2endTest, BlockingAuthMetadataPluginFailure) { Status s = stub_->Echo(&context, request, &response); EXPECT_FALSE(s.ok()); EXPECT_EQ(s.error_code(), StatusCode::UNAUTHENTICATED); - EXPECT_EQ(s.error_message(), kTestCredsPluginErrorMsg); + EXPECT_EQ(s.error_message(), + grpc::string("Getting metadata from plugin failed with error: ") + + kTestCredsPluginErrorMsg); } TEST_P(SecureEnd2endTest, ClientAuthContext) { From 85cc143a7f90c33453c3c822a1da514664f7baea Mon Sep 17 00:00:00 2001 From: Alexander Polcyn Date: Fri, 14 Jul 2017 16:36:51 -0700 Subject: [PATCH 082/127] fix memory leak with large metadata keys or values --- src/ruby/ext/grpc/rb_call.c | 33 +++++++++++++++------- src/ruby/ext/grpc/rb_call.h | 3 ++ src/ruby/ext/grpc/rb_call_credentials.c | 2 +- src/ruby/spec/client_server_spec.rb | 34 +++++++++++++++++++---- src/ruby/spec/generic/client_stub_spec.rb | 30 ++++++++++++++++++-- 5 files changed, 84 insertions(+), 18 deletions(-) diff --git a/src/ruby/ext/grpc/rb_call.c b/src/ruby/ext/grpc/rb_call.c index 67425a68e6f..b99954883f3 100644 --- a/src/ruby/ext/grpc/rb_call.c +++ b/src/ruby/ext/grpc/rb_call.c @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include "rb_byte_buffer.h" #include "rb_call_credentials.h" @@ -368,7 +370,7 @@ static VALUE grpc_rb_call_set_credentials(VALUE self, VALUE credentials) { to fill grpc_metadata_array. it's capacity should have been computed via a prior call to - grpc_rb_md_ary_fill_hash_cb + grpc_rb_md_ary_capacity_hash_cb */ static int grpc_rb_md_ary_fill_hash_cb(VALUE key, VALUE val, VALUE md_ary_obj) { grpc_metadata_array *md_ary = NULL; @@ -376,7 +378,7 @@ static int grpc_rb_md_ary_fill_hash_cb(VALUE key, VALUE val, VALUE md_ary_obj) { long i; grpc_slice key_slice; grpc_slice value_slice; - char *tmp_str; + char *tmp_str = NULL; if (TYPE(key) == T_SYMBOL) { key_slice = grpc_slice_from_static_string(rb_id2name(SYM2ID(key))); @@ -386,6 +388,7 @@ static int grpc_rb_md_ary_fill_hash_cb(VALUE key, VALUE val, VALUE md_ary_obj) { } else { rb_raise(rb_eTypeError, "grpc_rb_md_ary_fill_hash_cb: bad type for key parameter"); + return ST_STOP; } if (!grpc_header_key_is_legal(key_slice)) { @@ -413,6 +416,7 @@ static int grpc_rb_md_ary_fill_hash_cb(VALUE key, VALUE val, VALUE md_ary_obj) { tmp_str); return ST_STOP; } + GPR_ASSERT(md_ary->count < md_ary->capacity); md_ary->metadata[md_ary->count].key = key_slice; md_ary->metadata[md_ary->count].value = value_slice; md_ary->count += 1; @@ -428,6 +432,7 @@ static int grpc_rb_md_ary_fill_hash_cb(VALUE key, VALUE val, VALUE md_ary_obj) { tmp_str); return ST_STOP; } + GPR_ASSERT(md_ary->count < md_ary->capacity); md_ary->metadata[md_ary->count].key = key_slice; md_ary->metadata[md_ary->count].value = value_slice; md_ary->count += 1; @@ -435,7 +440,6 @@ static int grpc_rb_md_ary_fill_hash_cb(VALUE key, VALUE val, VALUE md_ary_obj) { rb_raise(rb_eArgError, "Header values must be of type string or array"); return ST_STOP; } - return ST_CONTINUE; } @@ -458,6 +462,7 @@ static int grpc_rb_md_ary_capacity_hash_cb(VALUE key, VALUE val, } else { md_ary->capacity += 1; } + return ST_CONTINUE; } @@ -480,7 +485,7 @@ void grpc_rb_md_ary_convert(VALUE md_ary_hash, grpc_metadata_array *md_ary) { md_ary_obj = TypedData_Wrap_Struct(grpc_rb_cMdAry, &grpc_rb_md_ary_data_type, md_ary); rb_hash_foreach(md_ary_hash, grpc_rb_md_ary_capacity_hash_cb, md_ary_obj); - md_ary->metadata = gpr_malloc(md_ary->capacity * sizeof(grpc_metadata)); + md_ary->metadata = gpr_zalloc(md_ary->capacity * sizeof(grpc_metadata)); rb_hash_foreach(md_ary_hash, grpc_rb_md_ary_fill_hash_cb, md_ary_obj); } @@ -611,13 +616,25 @@ static void grpc_run_batch_stack_init(run_batch_stack *st, st->write_flag = write_flag; } +void grpc_rb_metadata_array_destroy_including_entries( + grpc_metadata_array *array) { + size_t i; + if (array->metadata) { + for (i = 0; i < array->count; i++) { + grpc_slice_unref(array->metadata[i].key); + grpc_slice_unref(array->metadata[i].value); + } + } + grpc_metadata_array_destroy(array); +} + /* grpc_run_batch_stack_cleanup ensures the run_batch_stack is properly * cleaned up */ static void grpc_run_batch_stack_cleanup(run_batch_stack *st) { size_t i = 0; - grpc_metadata_array_destroy(&st->send_metadata); - grpc_metadata_array_destroy(&st->send_trailing_metadata); + grpc_rb_metadata_array_destroy_including_entries(&st->send_metadata); + grpc_rb_metadata_array_destroy_including_entries(&st->send_trailing_metadata); grpc_metadata_array_destroy(&st->recv_metadata); grpc_metadata_array_destroy(&st->recv_trailing_metadata); @@ -658,8 +675,6 @@ static void grpc_run_batch_stack_fill_ops(run_batch_stack *st, VALUE ops_hash) { st->ops[st->op_num].flags = 0; switch (NUM2INT(this_op)) { case GRPC_OP_SEND_INITIAL_METADATA: - /* N.B. later there is no need to explicitly delete the metadata keys - * and values, they are references to data in ruby objects. */ grpc_rb_md_ary_convert(this_value, &st->send_metadata); st->ops[st->op_num].data.send_initial_metadata.count = st->send_metadata.count; @@ -675,8 +690,6 @@ static void grpc_run_batch_stack_fill_ops(run_batch_stack *st, VALUE ops_hash) { case GRPC_OP_SEND_CLOSE_FROM_CLIENT: break; case GRPC_OP_SEND_STATUS_FROM_SERVER: - /* N.B. later there is no need to explicitly delete the metadata keys - * and values, they are references to data in ruby objects. */ grpc_rb_op_update_status_from_server( &st->ops[st->op_num], &st->send_trailing_metadata, &st->send_status_details, this_value); diff --git a/src/ruby/ext/grpc/rb_call.h b/src/ruby/ext/grpc/rb_call.h index be791cf9726..bfe8035e0fb 100644 --- a/src/ruby/ext/grpc/rb_call.h +++ b/src/ruby/ext/grpc/rb_call.h @@ -40,6 +40,9 @@ VALUE grpc_rb_md_ary_to_h(grpc_metadata_array *md_ary); */ void grpc_rb_md_ary_convert(VALUE md_ary_hash, grpc_metadata_array *md_ary); +void grpc_rb_metadata_array_destroy_including_entries( + grpc_metadata_array *md_ary); + /* grpc_rb_eCallError is the ruby class of the exception thrown during call operations. */ extern VALUE grpc_rb_eCallError; diff --git a/src/ruby/ext/grpc/rb_call_credentials.c b/src/ruby/ext/grpc/rb_call_credentials.c index 17083dd4146..049a869bdcf 100644 --- a/src/ruby/ext/grpc/rb_call_credentials.c +++ b/src/ruby/ext/grpc/rb_call_credentials.c @@ -108,7 +108,7 @@ static void grpc_rb_call_credentials_callback_with_gil(void *param) { error_details = StringValueCStr(details); params->callback(params->user_data, md_ary.metadata, md_ary.count, status, error_details); - grpc_metadata_array_destroy(&md_ary); + grpc_rb_metadata_array_destroy_including_entries(&md_ary); gpr_free(params); } diff --git a/src/ruby/spec/client_server_spec.rb b/src/ruby/spec/client_server_spec.rb index af3752c4ace..b48b4179ced 100644 --- a/src/ruby/spec/client_server_spec.rb +++ b/src/ruby/spec/client_server_spec.rb @@ -448,11 +448,18 @@ describe 'the secure http client/server' do it_behaves_like 'GRPC metadata delivery works OK' do end - it 'modifies metadata with CallCredentials' do - auth_proc = proc { { 'k1' => 'updated-v1' } } + def credentials_update_test(creds_update_md) + auth_proc = proc { creds_update_md } call_creds = GRPC::Core::CallCredentials.new(auth_proc) - md = { 'k2' => 'v2' } - expected_md = { 'k1' => 'updated-v1', 'k2' => 'v2' } + + initial_md_key = 'k2' + initial_md_val = 'v2' + initial_md = {} + initial_md[initial_md_key] = initial_md_val + expected_md = creds_update_md.clone + fail 'bad test param' unless expected_md[initial_md_key].nil? + expected_md[initial_md_key] = initial_md_val + recvd_rpc = nil rcv_thread = Thread.new do recvd_rpc = @server.request_call @@ -461,7 +468,7 @@ describe 'the secure http client/server' do call = new_client_call call.set_credentials! call_creds client_ops = { - CallOps::SEND_INITIAL_METADATA => md + CallOps::SEND_INITIAL_METADATA => initial_md } batch_result = call.run_batch(client_ops) expect(batch_result.send_metadata).to be true @@ -473,4 +480,21 @@ describe 'the secure http client/server' do replace_symbols = Hash[expected_md.each_pair.collect { |x, y| [x.to_s, y] }] expect(recvd_md).to eq(recvd_md.merge(replace_symbols)) end + + it 'modifies metadata with CallCredentials' do + credentials_update_test('k1' => 'updated-v1') + end + + it 'modifies large metadata with CallCredentials' do + val_array = %w( + '00000000000000000000000000000000000000000000000000000000000000', + '11111111111111111111111111111111111111111111111111111111111111', + ) + md = { + k3: val_array, + k4: '0000000000000000000000000000000000000000000000000000000000', + keeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeey5: 'v1' + } + credentials_update_test(md) + end end diff --git a/src/ruby/spec/generic/client_stub_spec.rb b/src/ruby/spec/generic/client_stub_spec.rb index a8653e73cfd..c2543dc388f 100644 --- a/src/ruby/spec/generic/client_stub_spec.rb +++ b/src/ruby/spec/generic/client_stub_spec.rb @@ -170,16 +170,42 @@ describe 'ClientStub' do th.join end - it 'should send metadata to the server ok' do + def metadata_test(md) server_port = create_test_server host = "localhost:#{server_port}" th = run_request_response(@sent_msg, @resp, @pass, - expected_metadata: { k1: 'v1', k2: 'v2' }) + expected_metadata: md) stub = GRPC::ClientStub.new(host, :this_channel_is_insecure) + @metadata = md expect(get_response(stub)).to eq(@resp) th.join end + it 'should send metadata to the server ok' do + metadata_test(k1: 'v1', k2: 'v2') + end + + # these tests mostly try to exercise when md might be allocated + # instead of inlined + it 'should send metadata with multiple large md to the server ok' do + val_array = %w( + '00000000000000000000000000000000000000000000000000000000000000', + '11111111111111111111111111111111111111111111111111111111111111', + '22222222222222222222222222222222222222222222222222222222222222', + ) + md = { + k1: val_array, + k2: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', + k3: 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb', + k4: 'cccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', + keeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeey5: 'v5', + 'k66666666666666666666666666666666666666666666666666666' => 'v6', + 'k77777777777777777777777777777777777777777777777777777' => 'v7', + 'k88888888888888888888888888888888888888888888888888888' => 'v8' + } + metadata_test(md) + end + it 'should send a request when configured using an override channel' do server_port = create_test_server alt_host = "localhost:#{server_port}" From 11fade7c140c86ff005fb0c040318f7c57075b43 Mon Sep 17 00:00:00 2001 From: Alexander Polcyn Date: Fri, 21 Jul 2017 19:22:10 -0700 Subject: [PATCH 083/127] Fix a ruby test flake --- src/ruby/spec/generic/client_stub_spec.rb | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/ruby/spec/generic/client_stub_spec.rb b/src/ruby/spec/generic/client_stub_spec.rb index a8653e73cfd..26cb970a1fa 100644 --- a/src/ruby/spec/generic/client_stub_spec.rb +++ b/src/ruby/spec/generic/client_stub_spec.rb @@ -451,10 +451,31 @@ describe 'ClientStub' do /Header values must be of type string or array/) end + def run_server_streamer_against_client_with_unmarshal_error( + expected_input, replys) + wakey_thread do |notifier| + c = expect_server_to_be_invoked(notifier) + expect(c.remote_read).to eq(expected_input) + begin + replys.each { |r| c.remote_send(r) } + rescue GRPC::Core::CallError + # An attempt to write to the client might fail. This is ok + # because the client call is expected to fail when + # unmarshalling the first response, and to cancel the call, + # and there is a race as for when the server-side call will + # start to fail. + p 'remote_send failed (allowed because call expected to cancel)' + ensure + c.send_status(OK, 'OK', true) + end + end + end + it 'the call terminates when there is an unmarshalling error' do server_port = create_test_server host = "localhost:#{server_port}" - th = run_server_streamer(@sent_msg, @replys, @pass) + th = run_server_streamer_against_client_with_unmarshal_error( + @sent_msg, @replys) stub = GRPC::ClientStub.new(host, :this_channel_is_insecure) unmarshal = proc { fail(ArgumentError, 'test unmarshalling error') } From ba65002de4dd443f9d3af0cbb6e129f673f39623 Mon Sep 17 00:00:00 2001 From: "hxcan.cai" Date: Mon, 24 Jul 2017 13:51:10 +0800 Subject: [PATCH 084/127] Fix error in Doxygen comment. --- include/grpc++/server.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/grpc++/server.h b/include/grpc++/server.h index 4684b10fe6d..01c4a60d216 100644 --- a/include/grpc++/server.h +++ b/include/grpc++/server.h @@ -159,7 +159,7 @@ class Server final : public ServerInterface, private GrpcLibraryCodegen { /// /// \param addr The address to try to bind to the server (eg, localhost:1234, /// 192.168.1.1:31416, [::1]:27182, etc.). - /// \params creds The credentials associated with the server. + /// \param creds The credentials associated with the server. /// /// \return bound port number on success, 0 on failure. /// From 4a8ecf047ca96bf692369ca0f942983fab0a0a06 Mon Sep 17 00:00:00 2001 From: Adele Zhou Date: Thu, 20 Jul 2017 16:28:32 -0700 Subject: [PATCH 085/127] Exit 1 if some tests fail. --- tools/run_tests/run_interop_tests.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/run_tests/run_interop_tests.py b/tools/run_tests/run_interop_tests.py index 1e702a86365..bde91159858 100755 --- a/tools/run_tests/run_interop_tests.py +++ b/tools/run_tests/run_interop_tests.py @@ -1230,6 +1230,11 @@ try: _HTTP2_TEST_CASES, http2_server_test_cases, resultset, num_failures, args.cloud_to_prod_auth or args.cloud_to_prod, args.prod_servers, args.http2_interop) + + if num_failures: + sys.exit(1) + else: + sys.exit(0) except Exception as e: print('exception occurred:') traceback.print_exc(file=sys.stdout) From 8f13439302b1b416f83c276e90e8de6cdf9bdec6 Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 24 Jul 2017 22:43:38 +0200 Subject: [PATCH 086/127] Fix issue from google/protobuf#1745 - javascript allow dot in filename --- src/compiler/node_generator.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/compiler/node_generator.cc b/src/compiler/node_generator.cc index 249ba086a57..355c11fcfcb 100644 --- a/src/compiler/node_generator.cc +++ b/src/compiler/node_generator.cc @@ -47,6 +47,7 @@ grpc::string ModuleAlias(const grpc::string filename) { grpc::string basename = grpc_generator::StripProto(filename); basename = grpc_generator::StringReplace(basename, "-", "$"); basename = grpc_generator::StringReplace(basename, "/", "_"); + basename = grpc_generator::StringReplace(basename, “.”, "_"); return basename + "_pb"; } From a178f406627916547037b63eb036f32d5db7c6d7 Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 24 Jul 2017 23:01:14 +0200 Subject: [PATCH 087/127] Fix quotation marks --- src/compiler/node_generator.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/node_generator.cc b/src/compiler/node_generator.cc index 355c11fcfcb..c0fef9128f1 100644 --- a/src/compiler/node_generator.cc +++ b/src/compiler/node_generator.cc @@ -47,7 +47,7 @@ grpc::string ModuleAlias(const grpc::string filename) { grpc::string basename = grpc_generator::StripProto(filename); basename = grpc_generator::StringReplace(basename, "-", "$"); basename = grpc_generator::StringReplace(basename, "/", "_"); - basename = grpc_generator::StringReplace(basename, “.”, "_"); + basename = grpc_generator::StringReplace(basename, ".", "_"); return basename + "_pb"; } From 84122c47b6274e71082e5b4bbc50289c096bb761 Mon Sep 17 00:00:00 2001 From: David Garcia Quintas Date: Mon, 24 Jul 2017 14:35:42 -0700 Subject: [PATCH 088/127] Fix wrong logging of LB policy addresses --- src/core/ext/filters/client_channel/lb_policy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/ext/filters/client_channel/lb_policy.c b/src/core/ext/filters/client_channel/lb_policy.c index 10b032214b8..dd95a135cf3 100644 --- a/src/core/ext/filters/client_channel/lb_policy.c +++ b/src/core/ext/filters/client_channel/lb_policy.c @@ -54,7 +54,7 @@ static gpr_atm ref_mutate(grpc_lb_policy *c, gpr_atm delta, #ifndef NDEBUG if (GRPC_TRACER_ON(grpc_trace_lb_policy_refcount)) { gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, - "LB_POLICY: 0x%p %12s 0x%" PRIxPTR " -> 0x%" PRIxPTR " [%s]", c, + "LB_POLICY: %p %12s 0x%" PRIxPTR " -> 0x%" PRIxPTR " [%s]", c, purpose, old_val, old_val + delta, reason); } #endif From 107840ffecca5e31d8363595656b262f092b2b01 Mon Sep 17 00:00:00 2001 From: Sree Kuchibhotla Date: Mon, 24 Jul 2017 18:45:09 -0700 Subject: [PATCH 089/127] Disable epoll1 unless explicitly requested --- src/core/lib/iomgr/ev_epoll1_linux.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/core/lib/iomgr/ev_epoll1_linux.c b/src/core/lib/iomgr/ev_epoll1_linux.c index 8db4a92453b..dc48d73df90 100644 --- a/src/core/lib/iomgr/ev_epoll1_linux.c +++ b/src/core/lib/iomgr/ev_epoll1_linux.c @@ -1030,6 +1030,12 @@ static const grpc_event_engine_vtable vtable = { /* It is possible that GLIBC has epoll but the underlying kernel doesn't. * Create a dummy epoll_fd to make sure epoll support is available */ const grpc_event_engine_vtable *grpc_init_epoll1_linux(bool explicit_request) { + /* TODO(sreek): Temporarily disable this poller unless explicitly requested + * via GRPC_POLL_STRATEGY */ + if (!explicit_request) { + return NULL; + } + if (!grpc_has_wakeup_fd()) { return NULL; } From 3d3403d3a8817a71d4bfb16e02e24fdcb5048f51 Mon Sep 17 00:00:00 2001 From: Guantao Liu Date: Mon, 24 Jul 2017 19:44:01 -0700 Subject: [PATCH 090/127] Update the scenario result schema --- .../run_tests/performance/scenario_result_schema.json | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tools/run_tests/performance/scenario_result_schema.json b/tools/run_tests/performance/scenario_result_schema.json index 245861f8c27..d7e2e292a7f 100644 --- a/tools/run_tests/performance/scenario_result_schema.json +++ b/tools/run_tests/performance/scenario_result_schema.json @@ -216,6 +216,16 @@ "name": "serverPollsPerRequest", "type": "FLOAT", "mode": "NULLABLE" + }, + { + "name": "serverQueriesPerCpuSec", + "type": "FLOAT", + "mode": "NULLABLE" + }, + { + "name": "clientQueriesPerCpuSec", + "type": "FLOAT", + "mode": "NULLABLE" } ] }, From 6abd20020b99514af9df381c72b509aeb88177a4 Mon Sep 17 00:00:00 2001 From: Vijay Pai Date: Tue, 25 Jul 2017 00:43:30 -0700 Subject: [PATCH 091/127] Revert "Separate internal-only and public parts of C++ API" --- include/grpc++/alarm.h | 2 +- include/grpc++/channel.h | 12 +- include/grpc++/impl/codegen/async_stream.h | 443 ++++++++---------- .../grpc++/impl/codegen/async_unary_call.h | 66 ++- include/grpc++/impl/codegen/call.h | 10 +- include/grpc++/impl/codegen/call_hook.h | 2 - .../grpc++/impl/codegen/channel_interface.h | 34 +- include/grpc++/impl/codegen/client_context.h | 28 +- .../grpc++/impl/codegen/client_unary_call.h | 4 +- .../grpc++/impl/codegen/completion_queue.h | 56 +-- .../impl/codegen/completion_queue_tag.h | 2 - include/grpc++/impl/codegen/metadata_map.h | 2 - .../grpc++/impl/codegen/method_handler_impl.h | 2 - include/grpc++/impl/codegen/rpc_method.h | 3 +- .../grpc++/impl/codegen/rpc_service_method.h | 3 +- include/grpc++/impl/codegen/server_context.h | 27 +- .../grpc++/impl/codegen/server_interface.h | 40 +- include/grpc++/impl/codegen/service_type.h | 46 +- include/grpc++/impl/codegen/sync_stream.h | 398 +++++++--------- include/grpc++/impl/codegen/time.h | 6 +- include/grpc++/server.h | 3 +- include/grpc++/server_builder.h | 1 + src/compiler/cpp_generator.cc | 199 ++++---- src/cpp/client/channel_cc.cc | 12 +- src/cpp/client/generic_stub.cc | 6 +- src/cpp/common/completion_queue_cc.cc | 2 +- .../health/default_health_check_service.cc | 9 +- .../health/default_health_check_service.h | 2 +- src/cpp/server/server_cc.cc | 69 ++- src/cpp/server/server_context.cc | 8 +- test/cpp/codegen/compiler_test_golden | 17 +- test/cpp/microbenchmarks/bm_cq.cc | 2 +- test/cpp/qps/server_sync.cc | 8 +- 33 files changed, 664 insertions(+), 860 deletions(-) diff --git a/include/grpc++/alarm.h b/include/grpc++/alarm.h index 00a9306d9d4..ed8dacbc944 100644 --- a/include/grpc++/alarm.h +++ b/include/grpc++/alarm.h @@ -77,7 +77,7 @@ class Alarm : private GrpcLibraryCodegen { void Cancel() { grpc_alarm_cancel(alarm_); } private: - class AlarmEntry : public internal::CompletionQueueTag { + class AlarmEntry : public CompletionQueueTag { public: AlarmEntry(void* tag) : tag_(tag) {} bool FinalizeResult(void** tag, bool* status) override { diff --git a/include/grpc++/channel.h b/include/grpc++/channel.h index 5ba3c591f05..c50091d6ac1 100644 --- a/include/grpc++/channel.h +++ b/include/grpc++/channel.h @@ -32,7 +32,7 @@ struct grpc_channel; namespace grpc { /// Channels represent a connection to an endpoint. Created by \a CreateChannel. class Channel final : public ChannelInterface, - public internal::CallHook, + public CallHook, public std::enable_shared_from_this, private GrpcLibraryCodegen { public: @@ -52,7 +52,7 @@ class Channel final : public ChannelInterface, private: template friend Status BlockingUnaryCall(ChannelInterface* channel, - const internal::RpcMethod& method, + const RpcMethod& method, ClientContext* context, const InputMessage& request, OutputMessage* result); @@ -60,11 +60,9 @@ class Channel final : public ChannelInterface, const grpc::string& host, grpc_channel* c_channel); Channel(const grpc::string& host, grpc_channel* c_channel); - internal::Call CreateCall(const internal::RpcMethod& method, - ClientContext* context, - CompletionQueue* cq) override; - void PerformOpsOnCall(internal::CallOpSetInterface* ops, - internal::Call* call) override; + Call CreateCall(const RpcMethod& method, ClientContext* context, + CompletionQueue* cq) override; + void PerformOpsOnCall(CallOpSetInterface* ops, Call* call) override; void* RegisterMethod(const char* method) override; void NotifyOnStateChangeImpl(grpc_connectivity_state last_observed, diff --git a/include/grpc++/impl/codegen/async_stream.h b/include/grpc++/impl/codegen/async_stream.h index ddbf3e655e9..9cf7ac30ddf 100644 --- a/include/grpc++/impl/codegen/async_stream.h +++ b/include/grpc++/impl/codegen/async_stream.h @@ -30,7 +30,6 @@ namespace grpc { class CompletionQueue; -namespace internal { /// Common interface for all client side asynchronous streaming. class ClientAsyncStreamingInterface { public: @@ -147,41 +146,9 @@ class AsyncWriterInterface { } }; -} // namespace internal - template -class ClientAsyncReaderInterface - : public internal::ClientAsyncStreamingInterface, - public internal::AsyncReaderInterface {}; - -/// Common interface for client side asynchronous writing. -template -class ClientAsyncWriterInterface - : public internal::ClientAsyncStreamingInterface, - public internal::AsyncWriterInterface { - public: - /// Signal the client is done with the writes (half-close the client stream). - /// Thread-safe with respect to \a AsyncReaderInterface::Read - /// - /// \param[in] tag The tag identifying the operation. - virtual void WritesDone(void* tag) = 0; -}; - -/// Async client-side interface for bi-directional streaming, -/// where the client-to-server message stream has messages of type \a W, -/// and the server-to-client message stream has messages of type \a R. -template -class ClientAsyncReaderWriterInterface - : public internal::ClientAsyncStreamingInterface, - public internal::AsyncWriterInterface, - public internal::AsyncReaderInterface { - public: - /// Signal the client is done with the writes (half-close the client stream). - /// Thread-safe with respect to \a AsyncReaderInterface::Read - /// - /// \param[in] tag The tag identifying the operation. - virtual void WritesDone(void* tag) = 0; -}; +class ClientAsyncReaderInterface : public ClientAsyncStreamingInterface, + public AsyncReaderInterface {}; /// Async client-side API for doing server-streaming RPCs, /// where the incoming message stream coming from the server has @@ -189,24 +156,21 @@ class ClientAsyncReaderWriterInterface template class ClientAsyncReader final : public ClientAsyncReaderInterface { public: - struct internal { - /// Create a stream and write the first request out. - /// \a tag will be notified on \a cq when the call has been started and - /// \a request has been written out. - /// Note that \a context will be used to fill in custom initial metadata - /// used to send to the server when starting the call. - template - static ClientAsyncReader* Create(::grpc::ChannelInterface* channel, - CompletionQueue* cq, - const ::grpc::internal::RpcMethod& method, - ClientContext* context, const W& request, - void* tag) { - ::grpc::internal::Call call = channel->CreateCall(method, context, cq); - return new (g_core_codegen_interface->grpc_call_arena_alloc( - call.call(), sizeof(ClientAsyncReader))) - ClientAsyncReader(call, context, request, tag); - } - }; + /// Create a stream and write the first request out. + /// \a tag will be notified on \a cq when the call has been started and + /// \a request has been written out. + /// Note that \a context will be used to fill in custom initial metadata + /// used to send to the server when starting the call. + template + static ClientAsyncReader* Create(ChannelInterface* channel, + CompletionQueue* cq, const RpcMethod& method, + ClientContext* context, const W& request, + void* tag) { + Call call = channel->CreateCall(method, context, cq); + return new (g_core_codegen_interface->grpc_call_arena_alloc( + call.call(), sizeof(ClientAsyncReader))) + ClientAsyncReader(call, context, request, tag); + } // always allocated against a call arena, no memory free required static void operator delete(void* ptr, std::size_t size) { @@ -254,8 +218,8 @@ class ClientAsyncReader final : public ClientAsyncReaderInterface { private: template - ClientAsyncReader(::grpc::internal::Call call, ClientContext* context, - const W& request, void* tag) + ClientAsyncReader(Call call, ClientContext* context, const W& request, + void* tag) : context_(context), call_(call) { init_ops_.set_output_tag(tag); init_ops_.SendInitialMetadata(context->send_initial_metadata_, @@ -267,19 +231,24 @@ class ClientAsyncReader final : public ClientAsyncReaderInterface { } ClientContext* context_; - ::grpc::internal::Call call_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, - ::grpc::internal::CallOpSendMessage, - ::grpc::internal::CallOpClientSendClose> + Call call_; + CallOpSet init_ops_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata> - meta_ops_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, - ::grpc::internal::CallOpRecvMessage> - read_ops_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, - ::grpc::internal::CallOpClientRecvStatus> - finish_ops_; + CallOpSet meta_ops_; + CallOpSet> read_ops_; + CallOpSet finish_ops_; +}; + +/// Common interface for client side asynchronous writing. +template +class ClientAsyncWriterInterface : public ClientAsyncStreamingInterface, + public AsyncWriterInterface { + public: + /// Signal the client is done with the writes (half-close the client stream). + /// Thread-safe with respect to \a AsyncReaderInterface::Read + /// + /// \param[in] tag The tag identifying the operation. + virtual void WritesDone(void* tag) = 0; }; /// Async API on the client side for doing client-streaming RPCs, @@ -288,27 +257,24 @@ class ClientAsyncReader final : public ClientAsyncReaderInterface { template class ClientAsyncWriter final : public ClientAsyncWriterInterface { public: - struct internal { - /// Create a stream and write the first request out. - /// \a tag will be notified on \a cq when the call has been started (i.e. - /// intitial metadata sent) and \a request has been written out. - /// Note that \a context will be used to fill in custom initial metadata - /// used to send to the server when starting the call. - /// \a response will be filled in with the single expected response - /// message from the server upon a successful call to the \a Finish - /// method of this instance. - template - static ClientAsyncWriter* Create(::grpc::ChannelInterface* channel, - CompletionQueue* cq, - const ::grpc::internal::RpcMethod& method, - ClientContext* context, R* response, - void* tag) { - ::grpc::internal::Call call = channel->CreateCall(method, context, cq); - return new (g_core_codegen_interface->grpc_call_arena_alloc( - call.call(), sizeof(ClientAsyncWriter))) - ClientAsyncWriter(call, context, response, tag); - } - }; + /// Create a stream and write the first request out. + /// \a tag will be notified on \a cq when the call has been started (i.e. + /// intitial metadata sent) and \a request has been written out. + /// Note that \a context will be used to fill in custom initial metadata + /// used to send to the server when starting the call. + /// \a response will be filled in with the single expected response + /// message from the server upon a successful call to the \a Finish + /// method of this instance. + template + static ClientAsyncWriter* Create(ChannelInterface* channel, + CompletionQueue* cq, const RpcMethod& method, + ClientContext* context, R* response, + void* tag) { + Call call = channel->CreateCall(method, context, cq); + return new (g_core_codegen_interface->grpc_call_arena_alloc( + call.call(), sizeof(ClientAsyncWriter))) + ClientAsyncWriter(call, context, response, tag); + } // always allocated against a call arena, no memory free required static void operator delete(void* ptr, std::size_t size) { @@ -372,8 +338,7 @@ class ClientAsyncWriter final : public ClientAsyncWriterInterface { private: template - ClientAsyncWriter(::grpc::internal::Call call, ClientContext* context, - R* response, void* tag) + ClientAsyncWriter(Call call, ClientContext* context, R* response, void* tag) : context_(context), call_(call) { finish_ops_.RecvMessage(response); finish_ops_.AllowNoMessage(); @@ -391,19 +356,30 @@ class ClientAsyncWriter final : public ClientAsyncWriterInterface { } ClientContext* context_; - ::grpc::internal::Call call_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata> - meta_ops_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, - ::grpc::internal::CallOpSendMessage, - ::grpc::internal::CallOpClientSendClose> + Call call_; + CallOpSet meta_ops_; + CallOpSet write_ops_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, - ::grpc::internal::CallOpGenericRecvMessage, - ::grpc::internal::CallOpClientRecvStatus> + CallOpSet finish_ops_; }; +/// Async client-side interface for bi-directional streaming, +/// where the client-to-server message stream has messages of type \a W, +/// and the server-to-client message stream has messages of type \a R. +template +class ClientAsyncReaderWriterInterface : public ClientAsyncStreamingInterface, + public AsyncWriterInterface, + public AsyncReaderInterface { + public: + /// Signal the client is done with the writes (half-close the client stream). + /// Thread-safe with respect to \a AsyncReaderInterface::Read + /// + /// \param[in] tag The tag identifying the operation. + virtual void WritesDone(void* tag) = 0; +}; + /// Async client-side interface for bi-directional streaming, /// where the outgoing message stream going to the server /// has messages of type \a W, and the incoming message stream coming @@ -412,23 +388,21 @@ template class ClientAsyncReaderWriter final : public ClientAsyncReaderWriterInterface { public: - struct internal { - /// Create a stream and write the first request out. - /// \a tag will be notified on \a cq when the call has been started (i.e. - /// intitial metadata sent). - /// Note that \a context will be used to fill in custom initial metadata - /// used to send to the server when starting the call. - static ClientAsyncReaderWriter* Create( - ::grpc::ChannelInterface* channel, CompletionQueue* cq, - const ::grpc::internal::RpcMethod& method, ClientContext* context, - void* tag) { - ::grpc::internal::Call call = channel->CreateCall(method, context, cq); - - return new (g_core_codegen_interface->grpc_call_arena_alloc( - call.call(), sizeof(ClientAsyncReaderWriter))) - ClientAsyncReaderWriter(call, context, tag); - } - }; + /// Create a stream and write the first request out. + /// \a tag will be notified on \a cq when the call has been started (i.e. + /// intitial metadata sent). + /// Note that \a context will be used to fill in custom initial metadata + /// used to send to the server when starting the call. + static ClientAsyncReaderWriter* Create(ChannelInterface* channel, + CompletionQueue* cq, + const RpcMethod& method, + ClientContext* context, void* tag) { + Call call = channel->CreateCall(method, context, cq); + + return new (g_core_codegen_interface->grpc_call_arena_alloc( + call.call(), sizeof(ClientAsyncReaderWriter))) + ClientAsyncReaderWriter(call, context, tag); + } // always allocated against a call arena, no memory free required static void operator delete(void* ptr, std::size_t size) { @@ -497,8 +471,7 @@ class ClientAsyncReaderWriter final } private: - ClientAsyncReaderWriter(::grpc::internal::Call call, ClientContext* context, - void* tag) + ClientAsyncReaderWriter(Call call, ClientContext* context, void* tag) : context_(context), call_(call) { if (context_->initial_metadata_corked_) { // if corked bit is set in context, we buffer up the initial metadata to @@ -514,25 +487,17 @@ class ClientAsyncReaderWriter final } ClientContext* context_; - ::grpc::internal::Call call_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata> - meta_ops_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, - ::grpc::internal::CallOpRecvMessage> - read_ops_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, - ::grpc::internal::CallOpSendMessage, - ::grpc::internal::CallOpClientSendClose> + Call call_; + CallOpSet meta_ops_; + CallOpSet> read_ops_; + CallOpSet write_ops_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, - ::grpc::internal::CallOpClientRecvStatus> - finish_ops_; + CallOpSet finish_ops_; }; template -class ServerAsyncReaderInterface - : public internal::ServerAsyncStreamingInterface, - public internal::AsyncReaderInterface { +class ServerAsyncReaderInterface : public ServerAsyncStreamingInterface, + public AsyncReaderInterface { public: /// Indicate that the stream is to be finished with a certain status code /// and also send out \a msg response to the client. @@ -576,89 +541,6 @@ class ServerAsyncReaderInterface virtual void FinishWithError(const Status& status, void* tag) = 0; }; -template -class ServerAsyncWriterInterface - : public internal::ServerAsyncStreamingInterface, - public internal::AsyncWriterInterface { - public: - /// Indicate that the stream is to be finished with a certain status code. - /// Request notification for when the server has sent the appropriate - /// signals to the client to end the call. - /// Should not be used concurrently with other operations. - /// - /// It is appropriate to call this method when either: - /// * all messages from the client have been received (either known - /// implictly, or explicitly because a previous \a - /// AsyncReaderInterface::Read operation with a non-ok - /// result (e.g., cq->Next(&read_tag, &ok) filled in 'ok' with 'false'. - /// * it is desired to end the call early with some non-OK status code. - /// - /// This operation will end when the server has finished sending out initial - /// metadata (if not sent already), response message, and status, or if - /// some failure occurred when trying to do so. - /// - /// \param[in] tag Tag identifying this request. - /// \param[in] status To be sent to the client as the result of this call. - virtual void Finish(const Status& status, void* tag) = 0; - - /// Request the writing of \a msg and coalesce it with trailing metadata which - /// contains \a status, using WriteOptions options with - /// identifying tag \a tag. - /// - /// WriteAndFinish is equivalent of performing WriteLast and Finish - /// in a single step. - /// - /// \param[in] msg The message to be written. - /// \param[in] options The WriteOptions to be used to write this message. - /// \param[in] status The Status that server returns to client. - /// \param[in] tag The tag identifying the operation. - virtual void WriteAndFinish(const W& msg, WriteOptions options, - const Status& status, void* tag) = 0; -}; - -/// Server-side interface for asynchronous bi-directional streaming. -template -class ServerAsyncReaderWriterInterface - : public internal::ServerAsyncStreamingInterface, - public internal::AsyncWriterInterface, - public internal::AsyncReaderInterface { - public: - /// Indicate that the stream is to be finished with a certain status code. - /// Request notification for when the server has sent the appropriate - /// signals to the client to end the call. - /// Should not be used concurrently with other operations. - /// - /// It is appropriate to call this method when either: - /// * all messages from the client have been received (either known - /// implictly, or explicitly because a previous \a - /// AsyncReaderInterface::Read operation - /// with a non-ok result (e.g., cq->Next(&read_tag, &ok) filled in 'ok' - /// with 'false'. - /// * it is desired to end the call early with some non-OK status code. - /// - /// This operation will end when the server has finished sending out initial - /// metadata (if not sent already), response message, and status, or if some - /// failure occurred when trying to do so. - /// - /// \param[in] tag Tag identifying this request. - /// \param[in] status To be sent to the client as the result of this call. - virtual void Finish(const Status& status, void* tag) = 0; - - /// Request the writing of \a msg and coalesce it with trailing metadata which - /// contains \a status, using WriteOptions options with - /// identifying tag \a tag. - /// - /// WriteAndFinish is equivalent of performing WriteLast and Finish in a - /// single step. - /// - /// \param[in] msg The message to be written. - /// \param[in] options The WriteOptions to be used to write this message. - /// \param[in] status The Status that server returns to client. - /// \param[in] tag The tag identifying the operation. - virtual void WriteAndFinish(const W& msg, WriteOptions options, - const Status& status, void* tag) = 0; -}; - /// Async server-side API for doing client-streaming RPCs, /// where the incoming message stream from the client has messages of type \a R, /// and the single response message sent from the server is type \a W. @@ -742,19 +624,56 @@ class ServerAsyncReader final : public ServerAsyncReaderInterface { } private: - void BindCall(::grpc::internal::Call* call) override { call_ = *call; } + void BindCall(Call* call) override { call_ = *call; } - ::grpc::internal::Call call_; + Call call_; ServerContext* ctx_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata> - meta_ops_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvMessage> read_ops_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, - ::grpc::internal::CallOpSendMessage, - ::grpc::internal::CallOpServerSendStatus> + CallOpSet meta_ops_; + CallOpSet> read_ops_; + CallOpSet finish_ops_; }; +template +class ServerAsyncWriterInterface : public ServerAsyncStreamingInterface, + public AsyncWriterInterface { + public: + /// Indicate that the stream is to be finished with a certain status code. + /// Request notification for when the server has sent the appropriate + /// signals to the client to end the call. + /// Should not be used concurrently with other operations. + /// + /// It is appropriate to call this method when either: + /// * all messages from the client have been received (either known + /// implictly, or explicitly because a previous \a + /// AsyncReaderInterface::Read operation with a non-ok + /// result (e.g., cq->Next(&read_tag, &ok) filled in 'ok' with 'false'. + /// * it is desired to end the call early with some non-OK status code. + /// + /// This operation will end when the server has finished sending out initial + /// metadata (if not sent already), response message, and status, or if + /// some failure occurred when trying to do so. + /// + /// \param[in] tag Tag identifying this request. + /// \param[in] status To be sent to the client as the result of this call. + virtual void Finish(const Status& status, void* tag) = 0; + + /// Request the writing of \a msg and coalesce it with trailing metadata which + /// contains \a status, using WriteOptions options with + /// identifying tag \a tag. + /// + /// WriteAndFinish is equivalent of performing WriteLast and Finish + /// in a single step. + /// + /// \param[in] msg The message to be written. + /// \param[in] options The WriteOptions to be used to write this message. + /// \param[in] status The Status that server returns to client. + /// \param[in] tag The tag identifying the operation. + virtual void WriteAndFinish(const W& msg, WriteOptions options, + const Status& status, void* tag) = 0; +}; + /// Async server-side API for doing server streaming RPCs, /// where the outgoing message stream from the server has messages of type \a W. template @@ -836,7 +755,7 @@ class ServerAsyncWriter final : public ServerAsyncWriterInterface { } private: - void BindCall(::grpc::internal::Call* call) override { call_ = *call; } + void BindCall(Call* call) override { call_ = *call; } template void EnsureInitialMetadataSent(T* ops) { @@ -850,17 +769,55 @@ class ServerAsyncWriter final : public ServerAsyncWriterInterface { } } - ::grpc::internal::Call call_; + Call call_; ServerContext* ctx_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata> - meta_ops_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, - ::grpc::internal::CallOpSendMessage, - ::grpc::internal::CallOpServerSendStatus> + CallOpSet meta_ops_; + CallOpSet write_ops_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, - ::grpc::internal::CallOpServerSendStatus> - finish_ops_; + CallOpSet finish_ops_; +}; + +/// Server-side interface for asynchronous bi-directional streaming. +template +class ServerAsyncReaderWriterInterface : public ServerAsyncStreamingInterface, + public AsyncWriterInterface, + public AsyncReaderInterface { + public: + /// Indicate that the stream is to be finished with a certain status code. + /// Request notification for when the server has sent the appropriate + /// signals to the client to end the call. + /// Should not be used concurrently with other operations. + /// + /// It is appropriate to call this method when either: + /// * all messages from the client have been received (either known + /// implictly, or explicitly because a previous \a + /// AsyncReaderInterface::Read operation + /// with a non-ok result (e.g., cq->Next(&read_tag, &ok) filled in 'ok' + /// with 'false'. + /// * it is desired to end the call early with some non-OK status code. + /// + /// This operation will end when the server has finished sending out initial + /// metadata (if not sent already), response message, and status, or if some + /// failure occurred when trying to do so. + /// + /// \param[in] tag Tag identifying this request. + /// \param[in] status To be sent to the client as the result of this call. + virtual void Finish(const Status& status, void* tag) = 0; + + /// Request the writing of \a msg and coalesce it with trailing metadata which + /// contains \a status, using WriteOptions options with + /// identifying tag \a tag. + /// + /// WriteAndFinish is equivalent of performing WriteLast and Finish in a + /// single step. + /// + /// \param[in] msg The message to be written. + /// \param[in] options The WriteOptions to be used to write this message. + /// \param[in] status The Status that server returns to client. + /// \param[in] tag The tag identifying the operation. + virtual void WriteAndFinish(const W& msg, WriteOptions options, + const Status& status, void* tag) = 0; }; /// Async server-side API for doing bidirectional streaming RPCs, @@ -955,7 +912,7 @@ class ServerAsyncReaderWriter final private: friend class ::grpc::Server; - void BindCall(::grpc::internal::Call* call) override { call_ = *call; } + void BindCall(Call* call) override { call_ = *call; } template void EnsureInitialMetadataSent(T* ops) { @@ -969,18 +926,14 @@ class ServerAsyncReaderWriter final } } - ::grpc::internal::Call call_; + Call call_; ServerContext* ctx_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata> - meta_ops_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvMessage> read_ops_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, - ::grpc::internal::CallOpSendMessage, - ::grpc::internal::CallOpServerSendStatus> + CallOpSet meta_ops_; + CallOpSet> read_ops_; + CallOpSet write_ops_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, - ::grpc::internal::CallOpServerSendStatus> - finish_ops_; + CallOpSet finish_ops_; }; } // namespace grpc diff --git a/include/grpc++/impl/codegen/async_unary_call.h b/include/grpc++/impl/codegen/async_unary_call.h index 45a8e8ee6af..41b3ae3f284 100644 --- a/include/grpc++/impl/codegen/async_unary_call.h +++ b/include/grpc++/impl/codegen/async_unary_call.h @@ -75,18 +75,17 @@ class ClientAsyncResponseReader final /// intitial metadata sent) and \a request has been written out. /// Note that \a context will be used to fill in custom initial metadata /// used to send to the server when starting the call. - struct internal { - template - static ClientAsyncResponseReader* Create( - ::grpc::ChannelInterface* channel, CompletionQueue* cq, - const ::grpc::internal::RpcMethod& method, ClientContext* context, - const W& request) { - ::grpc::internal::Call call = channel->CreateCall(method, context, cq); - return new (g_core_codegen_interface->grpc_call_arena_alloc( - call.call(), sizeof(ClientAsyncResponseReader))) - ClientAsyncResponseReader(call, context, request); - } - }; + template + static ClientAsyncResponseReader* Create(ChannelInterface* channel, + CompletionQueue* cq, + const RpcMethod& method, + ClientContext* context, + const W& request) { + Call call = channel->CreateCall(method, context, cq); + return new (g_core_codegen_interface->grpc_call_arena_alloc( + call.call(), sizeof(ClientAsyncResponseReader))) + ClientAsyncResponseReader(call, context, request); + } /// TODO(vjpai): Delete the below constructor /// PLEASE DO NOT USE THIS CONSTRUCTOR IN NEW CODE @@ -95,10 +94,9 @@ class ClientAsyncResponseReader final /// created this struct rather than properly using a stub. /// This code will not remain a valid public constructor for long. template - ClientAsyncResponseReader(::grpc::ChannelInterface* channel, - CompletionQueue* cq, - const ::grpc::internal::RpcMethod& method, - ClientContext* context, const W& request) + ClientAsyncResponseReader(ChannelInterface* channel, CompletionQueue* cq, + const RpcMethod& method, ClientContext* context, + const W& request) : context_(context), call_(channel->CreateCall(method, context, cq)), collection_(std::make_shared()) { @@ -166,11 +164,10 @@ class ClientAsyncResponseReader final private: ClientContext* const context_; - ::grpc::internal::Call call_; + Call call_; template - ClientAsyncResponseReader(::grpc::internal::Call call, ClientContext* context, - const W& request) + ClientAsyncResponseReader(Call call, ClientContext* context, const W& request) : context_(context), call_(call) { ops_.init_buf.SendInitialMetadata(context->send_initial_metadata_, context->initial_metadata_flags()); @@ -186,17 +183,13 @@ class ClientAsyncResponseReader final // TODO(vjpai): Remove the reference to CallOpSetCollectionInterface // as soon as the related workaround (public constructor) is deleted - struct Ops : public ::grpc::internal::CallOpSetCollectionInterface { - ::grpc::internal::SneakyCallOpSet< - ::grpc::internal::CallOpSendInitialMetadata, - ::grpc::internal::CallOpSendMessage, - ::grpc::internal::CallOpClientSendClose> + struct Ops : public CallOpSetCollectionInterface { + SneakyCallOpSet init_buf; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata> - meta_buf; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, - ::grpc::internal::CallOpRecvMessage, - ::grpc::internal::CallOpClientRecvStatus> + CallOpSet meta_buf; + CallOpSet, + CallOpClientRecvStatus> finish_buf; } ops_; @@ -208,8 +201,7 @@ class ClientAsyncResponseReader final /// Async server-side API for handling unary calls, where the single /// response message sent to the client is of type \a W. template -class ServerAsyncResponseWriter final - : public internal::ServerAsyncStreamingInterface { +class ServerAsyncResponseWriter final : public ServerAsyncStreamingInterface { public: explicit ServerAsyncResponseWriter(ServerContext* ctx) : call_(nullptr, nullptr, nullptr), ctx_(ctx) {} @@ -297,15 +289,13 @@ class ServerAsyncResponseWriter final } private: - void BindCall(::grpc::internal::Call* call) override { call_ = *call; } + void BindCall(Call* call) override { call_ = *call; } - ::grpc::internal::Call call_; + Call call_; ServerContext* ctx_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata> - meta_buf_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, - ::grpc::internal::CallOpSendMessage, - ::grpc::internal::CallOpServerSendStatus> + CallOpSet meta_buf_; + CallOpSet finish_buf_; }; diff --git a/include/grpc++/impl/codegen/call.h b/include/grpc++/impl/codegen/call.h index 9bbe7c63f43..f6eefb9f7ff 100644 --- a/include/grpc++/impl/codegen/call.h +++ b/include/grpc++/impl/codegen/call.h @@ -44,12 +44,10 @@ struct grpc_byte_buffer; namespace grpc { class ByteBuffer; -class CompletionQueue; -extern CoreCodegenInterface* g_core_codegen_interface; - -namespace internal { class Call; class CallHook; +class CompletionQueue; +extern CoreCodegenInterface* g_core_codegen_interface; const char kBinaryErrorDetailsKey[] = "grpc-status-details-bin"; @@ -78,7 +76,6 @@ inline grpc_metadata* FillMetadataArray( } return metadata_array; } -} // namespace internal /// Per-message write options. class WriteOptions { @@ -194,7 +191,6 @@ class WriteOptions { bool last_message_; }; -namespace internal { /// Default argument for CallOpSet. I is unused by the class, but can be /// used for generating multiple names for the same thing. template @@ -682,7 +678,7 @@ class Call final { grpc_call* call_; int max_receive_message_size_; }; -} // namespace internal + } // namespace grpc #endif // GRPCXX_IMPL_CODEGEN_CALL_H diff --git a/include/grpc++/impl/codegen/call_hook.h b/include/grpc++/impl/codegen/call_hook.h index 44e9de220ed..d026cc8b583 100644 --- a/include/grpc++/impl/codegen/call_hook.h +++ b/include/grpc++/impl/codegen/call_hook.h @@ -21,7 +21,6 @@ namespace grpc { -namespace internal { class CallOpSetInterface; class Call; @@ -32,7 +31,6 @@ class CallHook { virtual ~CallHook() {} virtual void PerformOpsOnCall(CallOpSetInterface* ops, Call* call) = 0; }; -} // namespace internal } // namespace grpc diff --git a/include/grpc++/impl/codegen/channel_interface.h b/include/grpc++/impl/codegen/channel_interface.h index cf1d77e905d..1b7590bf0c3 100644 --- a/include/grpc++/impl/codegen/channel_interface.h +++ b/include/grpc++/impl/codegen/channel_interface.h @@ -24,8 +24,10 @@ #include namespace grpc { -class ChannelInterface; +class Call; class ClientContext; +class RpcMethod; +class CallOpSetInterface; class CompletionQueue; template @@ -43,16 +45,6 @@ class ClientAsyncReaderWriter; template class ClientAsyncResponseReader; -namespace internal { -class Call; -class CallOpSetInterface; -class RpcMethod; -template -Status BlockingUnaryCall(ChannelInterface* channel, const RpcMethod& method, - ClientContext* context, const InputMessage& request, - OutputMessage* result); -} // namespace internal - /// Codegen interface for \a grpc::Channel. class ChannelInterface { public: @@ -104,16 +96,15 @@ class ChannelInterface { template friend class ::grpc::ClientAsyncResponseReader; template - friend Status(::grpc::internal::BlockingUnaryCall)( - ChannelInterface* channel, const internal::RpcMethod& method, - ClientContext* context, const InputMessage& request, - OutputMessage* result); - friend class ::grpc::internal::RpcMethod; - virtual internal::Call CreateCall(const internal::RpcMethod& method, - ClientContext* context, - CompletionQueue* cq) = 0; - virtual void PerformOpsOnCall(internal::CallOpSetInterface* ops, - internal::Call* call) = 0; + friend Status BlockingUnaryCall(ChannelInterface* channel, + const RpcMethod& method, + ClientContext* context, + const InputMessage& request, + OutputMessage* result); + friend class ::grpc::RpcMethod; + virtual Call CreateCall(const RpcMethod& method, ClientContext* context, + CompletionQueue* cq) = 0; + virtual void PerformOpsOnCall(CallOpSetInterface* ops, Call* call) = 0; virtual void* RegisterMethod(const char* method) = 0; virtual void NotifyOnStateChangeImpl(grpc_connectivity_state last_observed, gpr_timespec deadline, @@ -121,6 +112,7 @@ class ChannelInterface { virtual bool WaitForStateChangeImpl(grpc_connectivity_state last_observed, gpr_timespec deadline) = 0; }; + } // namespace grpc #endif // GRPCXX_IMPL_CODEGEN_CHANNEL_INTERFACE_H diff --git a/include/grpc++/impl/codegen/client_context.h b/include/grpc++/impl/codegen/client_context.h index 89eb8b976e0..6d7e13bbf29 100644 --- a/include/grpc++/impl/codegen/client_context.h +++ b/include/grpc++/impl/codegen/client_context.h @@ -60,18 +60,7 @@ class Channel; class ChannelInterface; class CompletionQueue; class CallCredentials; -class ClientContext; - -namespace internal { class RpcMethod; -class CallOpClientRecvStatus; -class CallOpRecvInitialMetadata; -template -Status BlockingUnaryCall(ChannelInterface* channel, const RpcMethod& method, - ClientContext* context, const InputMessage& request, - OutputMessage* result); -} // namespace internal - template class ClientReader; template @@ -356,8 +345,8 @@ class ClientContext { ClientContext& operator=(const ClientContext&); friend class ::grpc::testing::InteropClientContextInspector; - friend class ::grpc::internal::CallOpClientRecvStatus; - friend class ::grpc::internal::CallOpRecvInitialMetadata; + friend class CallOpClientRecvStatus; + friend class CallOpRecvInitialMetadata; friend class Channel; template friend class ::grpc::ClientReader; @@ -374,10 +363,11 @@ class ClientContext { template friend class ::grpc::ClientAsyncResponseReader; template - friend Status(::grpc::internal::BlockingUnaryCall)( - ChannelInterface* channel, const internal::RpcMethod& method, - ClientContext* context, const InputMessage& request, - OutputMessage* result); + friend Status BlockingUnaryCall(ChannelInterface* channel, + const RpcMethod& method, + ClientContext* context, + const InputMessage& request, + OutputMessage* result); grpc_call* call() const { return call_; } void set_call(grpc_call* call, const std::shared_ptr& channel); @@ -409,8 +399,8 @@ class ClientContext { mutable std::shared_ptr auth_context_; struct census_context* census_context_; std::multimap send_initial_metadata_; - internal::MetadataMap recv_initial_metadata_; - internal::MetadataMap trailing_metadata_; + MetadataMap recv_initial_metadata_; + MetadataMap trailing_metadata_; grpc_call* propagate_from_call_; PropagationOptions propagation_options_; diff --git a/include/grpc++/impl/codegen/client_unary_call.h b/include/grpc++/impl/codegen/client_unary_call.h index 8fef3ab353a..7c540fade9d 100644 --- a/include/grpc++/impl/codegen/client_unary_call.h +++ b/include/grpc++/impl/codegen/client_unary_call.h @@ -30,9 +30,8 @@ namespace grpc { class Channel; class ClientContext; class CompletionQueue; - -namespace internal { class RpcMethod; + /// Wrapper that performs a blocking unary call template Status BlockingUnaryCall(ChannelInterface* channel, const RpcMethod& method, @@ -68,7 +67,6 @@ Status BlockingUnaryCall(ChannelInterface* channel, const RpcMethod& method, return status; } -} // namespace internal } // namespace grpc #endif // GRPCXX_IMPL_CODEGEN_CLIENT_UNARY_CALL_H diff --git a/include/grpc++/impl/codegen/completion_queue.h b/include/grpc++/impl/codegen/completion_queue.h index a04778aa721..ca757e2a9c5 100644 --- a/include/grpc++/impl/codegen/completion_queue.h +++ b/include/grpc++/impl/codegen/completion_queue.h @@ -56,19 +56,7 @@ class ServerWriter; namespace internal { template class ServerReaderWriterBody; -} // namespace internal - -class Channel; -class ChannelInterface; -class ClientContext; -class CompletionQueue; -class Server; -class ServerBuilder; -class ServerContext; - -namespace internal { -class CompletionQueueTag; -class RpcMethod; +} template class RpcMethodHandler; template @@ -78,13 +66,16 @@ class ServerStreamingHandler; template class BidiStreamingHandler; class UnknownMethodHandler; -template -class TemplatedBidiStreamingHandler; -template -Status BlockingUnaryCall(ChannelInterface* channel, const RpcMethod& method, - ClientContext* context, const InputMessage& request, - OutputMessage* result); -} // namespace internal + +class Channel; +class ChannelInterface; +class ClientContext; +class CompletionQueueTag; +class CompletionQueue; +class RpcMethod; +class Server; +class ServerBuilder; +class ServerContext; extern CoreCodegenInterface* g_core_codegen_interface; @@ -205,27 +196,28 @@ class CompletionQueue : private GrpcLibraryCodegen { template friend class ::grpc::internal::ServerReaderWriterBody; template - friend class ::grpc::internal::RpcMethodHandler; + friend class RpcMethodHandler; template - friend class ::grpc::internal::ClientStreamingHandler; + friend class ClientStreamingHandler; template - friend class ::grpc::internal::ServerStreamingHandler; + friend class ServerStreamingHandler; template - friend class ::grpc::internal::TemplatedBidiStreamingHandler; - friend class ::grpc::internal::UnknownMethodHandler; + friend class TemplatedBidiStreamingHandler; + friend class UnknownMethodHandler; friend class ::grpc::Server; friend class ::grpc::ServerContext; template - friend Status(::grpc::internal::BlockingUnaryCall)( - ChannelInterface* channel, const internal::RpcMethod& method, - ClientContext* context, const InputMessage& request, - OutputMessage* result); + friend Status BlockingUnaryCall(ChannelInterface* channel, + const RpcMethod& method, + ClientContext* context, + const InputMessage& request, + OutputMessage* result); NextStatus AsyncNextInternal(void** tag, bool* ok, gpr_timespec deadline); /// Wraps \a grpc_completion_queue_pluck. /// \warning Must not be mixed with calls to \a Next. - bool Pluck(internal::CompletionQueueTag* tag) { + bool Pluck(CompletionQueueTag* tag) { auto deadline = g_core_codegen_interface->gpr_inf_future(GPR_CLOCK_REALTIME); auto ev = g_core_codegen_interface->grpc_completion_queue_pluck( @@ -246,7 +238,7 @@ class CompletionQueue : private GrpcLibraryCodegen { /// implementation to simple call the other TryPluck function with a zero /// timeout. i.e: /// TryPluck(tag, gpr_time_0(GPR_CLOCK_REALTIME)) - void TryPluck(internal::CompletionQueueTag* tag) { + void TryPluck(CompletionQueueTag* tag) { auto deadline = g_core_codegen_interface->gpr_time_0(GPR_CLOCK_REALTIME); auto ev = g_core_codegen_interface->grpc_completion_queue_pluck( cq_, tag, deadline, nullptr); @@ -262,7 +254,7 @@ class CompletionQueue : private GrpcLibraryCodegen { /// /// This exects tag->FinalizeResult (if called) to return 'false' i.e expects /// that the tag is internal not something that is returned to the user. - void TryPluck(internal::CompletionQueueTag* tag, gpr_timespec deadline) { + void TryPluck(CompletionQueueTag* tag, gpr_timespec deadline) { auto ev = g_core_codegen_interface->grpc_completion_queue_pluck( cq_, tag, deadline, nullptr); if (ev.type == GRPC_QUEUE_TIMEOUT || ev.type == GRPC_QUEUE_SHUTDOWN) { diff --git a/include/grpc++/impl/codegen/completion_queue_tag.h b/include/grpc++/impl/codegen/completion_queue_tag.h index cb16bcf9ff5..4d7d3a98dd8 100644 --- a/include/grpc++/impl/codegen/completion_queue_tag.h +++ b/include/grpc++/impl/codegen/completion_queue_tag.h @@ -21,7 +21,6 @@ namespace grpc { -namespace internal { /// An interface allowing implementors to process and filter event tags. class CompletionQueueTag { public: @@ -32,7 +31,6 @@ class CompletionQueueTag { /// queue virtual bool FinalizeResult(void** tag, bool* status) = 0; }; -} // namespace internal } // namespace grpc diff --git a/include/grpc++/impl/codegen/metadata_map.h b/include/grpc++/impl/codegen/metadata_map.h index fd4750efdd1..b73985967d3 100644 --- a/include/grpc++/impl/codegen/metadata_map.h +++ b/include/grpc++/impl/codegen/metadata_map.h @@ -23,7 +23,6 @@ namespace grpc { -namespace internal { class MetadataMap { public: MetadataMap() { memset(&arr_, 0, sizeof(arr_)); } @@ -51,7 +50,6 @@ class MetadataMap { grpc_metadata_array arr_; std::multimap map_; }; -} // namespace internal } // namespace grpc diff --git a/include/grpc++/impl/codegen/method_handler_impl.h b/include/grpc++/impl/codegen/method_handler_impl.h index 87e9e5e9522..15e24bdcdcb 100644 --- a/include/grpc++/impl/codegen/method_handler_impl.h +++ b/include/grpc++/impl/codegen/method_handler_impl.h @@ -25,7 +25,6 @@ namespace grpc { -namespace internal { /// A wrapper class of an application provided rpc method handler. template class RpcMethodHandler : public MethodHandler { @@ -266,7 +265,6 @@ class UnknownMethodHandler : public MethodHandler { } }; -} // namespace internal } // namespace grpc #endif // GRPCXX_IMPL_CODEGEN_METHOD_HANDLER_IMPL_H diff --git a/include/grpc++/impl/codegen/rpc_method.h b/include/grpc++/impl/codegen/rpc_method.h index 54e52364ef3..ac13ac56c7a 100644 --- a/include/grpc++/impl/codegen/rpc_method.h +++ b/include/grpc++/impl/codegen/rpc_method.h @@ -24,7 +24,7 @@ #include namespace grpc { -namespace internal { + /// Descriptor of an RPC method class RpcMethod { public: @@ -55,7 +55,6 @@ class RpcMethod { void* const channel_tag_; }; -} // namespace internal } // namespace grpc #endif // GRPCXX_IMPL_CODEGEN_RPC_METHOD_H diff --git a/include/grpc++/impl/codegen/rpc_service_method.h b/include/grpc++/impl/codegen/rpc_service_method.h index 635e40469b2..7165774172c 100644 --- a/include/grpc++/impl/codegen/rpc_service_method.h +++ b/include/grpc++/impl/codegen/rpc_service_method.h @@ -35,8 +35,8 @@ struct grpc_byte_buffer; namespace grpc { class ServerContext; +class StreamContextInterface; -namespace internal { /// Base class for running an RPC handler. class MethodHandler { public: @@ -71,7 +71,6 @@ class RpcServiceMethod : public RpcMethod { void* server_tag_; std::unique_ptr handler_; }; -} // namespace internal } // namespace grpc diff --git a/include/grpc++/impl/codegen/server_context.h b/include/grpc++/impl/codegen/server_context.h index a2d6967bf84..b5e37fd12b1 100644 --- a/include/grpc++/impl/codegen/server_context.h +++ b/include/grpc++/impl/codegen/server_context.h @@ -55,6 +55,7 @@ class ServerWriter; namespace internal { template class ServerReaderWriterBody; +} template class RpcMethodHandler; template @@ -64,11 +65,9 @@ class ServerStreamingHandler; template class BidiStreamingHandler; class UnknownMethodHandler; -template -class TemplatedBidiStreamingHandler; -class Call; -} // namespace internal +class Call; +class CallOpBuffer; class CompletionQueue; class Server; class ServerInterface; @@ -248,14 +247,14 @@ class ServerContext { template friend class ::grpc::internal::ServerReaderWriterBody; template - friend class ::grpc::internal::RpcMethodHandler; + friend class RpcMethodHandler; template - friend class ::grpc::internal::ClientStreamingHandler; + friend class ClientStreamingHandler; template - friend class ::grpc::internal::ServerStreamingHandler; + friend class ServerStreamingHandler; template - friend class ::grpc::internal::TemplatedBidiStreamingHandler; - friend class ::grpc::internal::UnknownMethodHandler; + friend class TemplatedBidiStreamingHandler; + friend class UnknownMethodHandler; friend class ::grpc::ClientContext; /// Prevent copying. @@ -264,9 +263,9 @@ class ServerContext { class CompletionOp; - void BeginCompletionOp(internal::Call* call); + void BeginCompletionOp(Call* call); /// Return the tag queued by BeginCompletionOp() - internal::CompletionQueueTag* GetCompletionOpTag(); + CompletionQueueTag* GetCompletionOpTag(); ServerContext(gpr_timespec deadline, grpc_metadata_array* arr); @@ -283,7 +282,7 @@ class ServerContext { CompletionQueue* cq_; bool sent_initial_metadata_; mutable std::shared_ptr auth_context_; - internal::MetadataMap client_metadata_; + MetadataMap client_metadata_; std::multimap initial_metadata_; std::multimap trailing_metadata_; @@ -291,9 +290,7 @@ class ServerContext { grpc_compression_level compression_level_; grpc_compression_algorithm compression_algorithm_; - internal::CallOpSet - pending_ops_; + CallOpSet pending_ops_; bool has_pending_ops_; }; diff --git a/include/grpc++/impl/codegen/server_interface.h b/include/grpc++/impl/codegen/server_interface.h index 3bcf4c87e7c..ef063a9718c 100644 --- a/include/grpc++/impl/codegen/server_interface.h +++ b/include/grpc++/impl/codegen/server_interface.h @@ -30,21 +30,20 @@ namespace grpc { class AsyncGenericService; class Channel; class GenericServerContext; +class RpcService; +class ServerAsyncStreamingInterface; class ServerCompletionQueue; class ServerContext; class ServerCredentials; class Service; +class ThreadPoolInterface; extern CoreCodegenInterface* g_core_codegen_interface; /// Models a gRPC server. /// /// Servers are configured and started via \a grpc::ServerBuilder. -namespace internal { -class ServerAsyncStreamingInterface; -} // namespace internal - -class ServerInterface : public internal::CallHook { +class ServerInterface : public CallHook { public: virtual ~ServerInterface() {} @@ -79,7 +78,7 @@ class ServerInterface : public internal::CallHook { virtual void Wait() = 0; protected: - friend class ::grpc::Service; + friend class Service; /// Register a service. This call does not take ownership of the service. /// The service must exist for the lifetime of the Server instance. @@ -117,13 +116,12 @@ class ServerInterface : public internal::CallHook { virtual grpc_server* server() = 0; - virtual void PerformOpsOnCall(internal::CallOpSetInterface* ops, - internal::Call* call) = 0; + virtual void PerformOpsOnCall(CallOpSetInterface* ops, Call* call) = 0; - class BaseAsyncRequest : public internal::CompletionQueueTag { + class BaseAsyncRequest : public CompletionQueueTag { public: BaseAsyncRequest(ServerInterface* server, ServerContext* context, - internal::ServerAsyncStreamingInterface* stream, + ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, void* tag, bool delete_on_finalize); virtual ~BaseAsyncRequest(); @@ -133,7 +131,7 @@ class ServerInterface : public internal::CallHook { protected: ServerInterface* const server_; ServerContext* const context_; - internal::ServerAsyncStreamingInterface* const stream_; + ServerAsyncStreamingInterface* const stream_; CompletionQueue* const call_cq_; void* const tag_; const bool delete_on_finalize_; @@ -143,7 +141,7 @@ class ServerInterface : public internal::CallHook { class RegisteredAsyncRequest : public BaseAsyncRequest { public: RegisteredAsyncRequest(ServerInterface* server, ServerContext* context, - internal::ServerAsyncStreamingInterface* stream, + ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, void* tag); // uses BaseAsyncRequest::FinalizeResult @@ -157,7 +155,7 @@ class ServerInterface : public internal::CallHook { public: NoPayloadAsyncRequest(void* registered_method, ServerInterface* server, ServerContext* context, - internal::ServerAsyncStreamingInterface* stream, + ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, ServerCompletionQueue* notification_cq, void* tag) : RegisteredAsyncRequest(server, context, stream, call_cq, tag) { @@ -172,7 +170,7 @@ class ServerInterface : public internal::CallHook { public: PayloadAsyncRequest(void* registered_method, ServerInterface* server, ServerContext* context, - internal::ServerAsyncStreamingInterface* stream, + ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, ServerCompletionQueue* notification_cq, void* tag, Message* request) @@ -225,7 +223,7 @@ class ServerInterface : public internal::CallHook { class GenericAsyncRequest : public BaseAsyncRequest { public: GenericAsyncRequest(ServerInterface* server, GenericServerContext* context, - internal::ServerAsyncStreamingInterface* stream, + ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, ServerCompletionQueue* notification_cq, void* tag, bool delete_on_finalize); @@ -237,9 +235,8 @@ class ServerInterface : public internal::CallHook { }; template - void RequestAsyncCall(internal::RpcServiceMethod* method, - ServerContext* context, - internal::ServerAsyncStreamingInterface* stream, + void RequestAsyncCall(RpcServiceMethod* method, ServerContext* context, + ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, ServerCompletionQueue* notification_cq, void* tag, Message* message) { @@ -249,9 +246,8 @@ class ServerInterface : public internal::CallHook { message); } - void RequestAsyncCall(internal::RpcServiceMethod* method, - ServerContext* context, - internal::ServerAsyncStreamingInterface* stream, + void RequestAsyncCall(RpcServiceMethod* method, ServerContext* context, + ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, ServerCompletionQueue* notification_cq, void* tag) { GPR_CODEGEN_ASSERT(method); @@ -260,7 +256,7 @@ class ServerInterface : public internal::CallHook { } void RequestAsyncGenericCall(GenericServerContext* context, - internal::ServerAsyncStreamingInterface* stream, + ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, ServerCompletionQueue* notification_cq, void* tag) { diff --git a/include/grpc++/impl/codegen/service_type.h b/include/grpc++/impl/codegen/service_type.h index 71c3d99d5c5..2dc4ea0ea65 100644 --- a/include/grpc++/impl/codegen/service_type.h +++ b/include/grpc++/impl/codegen/service_type.h @@ -28,14 +28,13 @@ namespace grpc { +class Call; class CompletionQueue; class Server; class ServerInterface; class ServerCompletionQueue; class ServerContext; -namespace internal { -class Call; class ServerAsyncStreamingInterface { public: virtual ~ServerAsyncStreamingInterface() {} @@ -49,10 +48,9 @@ class ServerAsyncStreamingInterface { virtual void SendInitialMetadata(void* tag) = 0; private: - friend class ::grpc::ServerInterface; + friend class ServerInterface; virtual void BindCall(Call* call) = 0; }; -} // namespace internal /// Desriptor of an RPC service and its various RPC methods class Service { @@ -90,38 +88,40 @@ class Service { protected: template void RequestAsyncUnary(int index, ServerContext* context, Message* request, - internal::ServerAsyncStreamingInterface* stream, + ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, ServerCompletionQueue* notification_cq, void* tag) { server_->RequestAsyncCall(methods_[index].get(), context, stream, call_cq, notification_cq, tag, request); } - void RequestAsyncClientStreaming( - int index, ServerContext* context, - internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, - ServerCompletionQueue* notification_cq, void* tag) { + void RequestAsyncClientStreaming(int index, ServerContext* context, + ServerAsyncStreamingInterface* stream, + CompletionQueue* call_cq, + ServerCompletionQueue* notification_cq, + void* tag) { server_->RequestAsyncCall(methods_[index].get(), context, stream, call_cq, notification_cq, tag); } template - void RequestAsyncServerStreaming( - int index, ServerContext* context, Message* request, - internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, - ServerCompletionQueue* notification_cq, void* tag) { + void RequestAsyncServerStreaming(int index, ServerContext* context, + Message* request, + ServerAsyncStreamingInterface* stream, + CompletionQueue* call_cq, + ServerCompletionQueue* notification_cq, + void* tag) { server_->RequestAsyncCall(methods_[index].get(), context, stream, call_cq, notification_cq, tag, request); } - void RequestAsyncBidiStreaming( - int index, ServerContext* context, - internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, - ServerCompletionQueue* notification_cq, void* tag) { + void RequestAsyncBidiStreaming(int index, ServerContext* context, + ServerAsyncStreamingInterface* stream, + CompletionQueue* call_cq, + ServerCompletionQueue* notification_cq, + void* tag) { server_->RequestAsyncCall(methods_[index].get(), context, stream, call_cq, notification_cq, tag); } - void AddMethod(internal::RpcServiceMethod* method) { - methods_.emplace_back(method); - } + void AddMethod(RpcServiceMethod* method) { methods_.emplace_back(method); } void MarkMethodAsync(int index) { GPR_CODEGEN_ASSERT( @@ -139,7 +139,7 @@ class Service { methods_[index].reset(); } - void MarkMethodStreamed(int index, internal::MethodHandler* streamed_method) { + void MarkMethodStreamed(int index, MethodHandler* streamed_method) { GPR_CODEGEN_ASSERT(methods_[index] && methods_[index]->handler() && "Cannot mark an async or generic method Streamed"); methods_[index]->SetHandler(streamed_method); @@ -148,14 +148,14 @@ class Service { // case of BIDI_STREAMING that has 1 read and 1 write, in that order, // and split server-side streaming is BIDI_STREAMING with 1 read and // any number of writes, in that order. - methods_[index]->SetMethodType(internal::RpcMethod::BIDI_STREAMING); + methods_[index]->SetMethodType(::grpc::RpcMethod::BIDI_STREAMING); } private: friend class Server; friend class ServerInterface; ServerInterface* server_; - std::vector> methods_; + std::vector> methods_; }; } // namespace grpc diff --git a/include/grpc++/impl/codegen/sync_stream.h b/include/grpc++/impl/codegen/sync_stream.h index f9c83030003..3fa208963db 100644 --- a/include/grpc++/impl/codegen/sync_stream.h +++ b/include/grpc++/impl/codegen/sync_stream.h @@ -30,7 +30,6 @@ namespace grpc { -namespace internal { /// Common interface for all synchronous client side streaming. class ClientStreamingInterface { public: @@ -63,6 +62,20 @@ class ClientStreamingInterface { virtual Status Finish() = 0; }; +/// Common interface for all synchronous server side streaming. +class ServerStreamingInterface { + public: + virtual ~ServerStreamingInterface() {} + + /// Block to send initial metadata to client. + /// This call is optional, but if it is used, it cannot be used concurrently + /// with or after the \a Finish method. + /// + /// The initial metadata that will be sent to the client will be + /// taken from the \a ServerContext associated with the call. + virtual void SendInitialMetadata() = 0; +}; + /// An interface that yields a sequence of messages of type \a R. template class ReaderInterface { @@ -128,55 +141,16 @@ class WriterInterface { } }; -} // namespace internal - /// Client-side interface for streaming reads of message of type \a R. template -class ClientReaderInterface : public internal::ClientStreamingInterface, - public internal::ReaderInterface { - public: - /// Block to wait for initial metadata from server. The received metadata - /// can only be accessed after this call returns. Should only be called before - /// the first read. Calling this method is optional, and if it is not called - /// the metadata will be available in ClientContext after the first read. - virtual void WaitForInitialMetadata() = 0; -}; - -/// Client-side interface for streaming writes of message type \a W. -template -class ClientWriterInterface : public internal::ClientStreamingInterface, - public internal::WriterInterface { - public: - /// Half close writing from the client. (signal that the stream of messages - /// coming from the clinet is complete). - /// Blocks until currently-pending writes are completed. - /// Thread safe with respect to \a ReaderInterface::Read operations only - /// - /// \return Whether the writes were successful. - virtual bool WritesDone() = 0; -}; - -/// Client-side interface for bi-directional streaming with -/// client-to-server stream messages of type \a W and -/// server-to-client stream messages of type \a R. -template -class ClientReaderWriterInterface : public internal::ClientStreamingInterface, - public internal::WriterInterface, - public internal::ReaderInterface { +class ClientReaderInterface : public ClientStreamingInterface, + public ReaderInterface { public: /// Block to wait for initial metadata from server. The received metadata /// can only be accessed after this call returns. Should only be called before /// the first read. Calling this method is optional, and if it is not called /// the metadata will be available in ClientContext after the first read. virtual void WaitForInitialMetadata() = 0; - - /// Half close writing from the client. (signal that the stream of messages - /// coming from the clinet is complete). - /// Blocks until currently-pending writes are completed. - /// Thread-safe with respect to \a ReaderInterface::Read - /// - /// \return Whether the writes were successful. - virtual bool WritesDone() = 0; }; /// Synchronous (blocking) client-side API for doing server-streaming RPCs, @@ -185,14 +159,28 @@ class ClientReaderWriterInterface : public internal::ClientStreamingInterface, template class ClientReader final : public ClientReaderInterface { public: - struct internal { - template - static ClientReader* Create(::grpc::ChannelInterface* channel, - const ::grpc::internal::RpcMethod& method, - ClientContext* context, const W& request) { - return new ClientReader(channel, method, context, request); - } - }; + /// Block to create a stream and write the initial metadata and \a request + /// out. Note that \a context will be used to fill in custom initial + /// metadata used to send to the server when starting the call. + template + ClientReader(ChannelInterface* channel, const RpcMethod& method, + ClientContext* context, const W& request) + : context_(context), + cq_(grpc_completion_queue_attributes{ + GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, + GRPC_CQ_DEFAULT_POLLING}), // Pluckable cq + call_(channel->CreateCall(method, context, &cq_)) { + CallOpSet + ops; + ops.SendInitialMetadata(context->send_initial_metadata_, + context->initial_metadata_flags()); + // TODO(ctiller): don't assert + GPR_CODEGEN_ASSERT(ops.SendMessage(request).ok()); + ops.ClientSendClose(); + call_.PerformOps(&ops); + cq_.Pluck(&ops); + } /// See the \a ClientStreamingInterface.WaitForInitialMetadata method for /// semantics. @@ -204,8 +192,7 @@ class ClientReader final : public ClientReaderInterface { void WaitForInitialMetadata() override { GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_); - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata> - ops; + CallOpSet ops; ops.RecvInitialMetadata(context_); call_.PerformOps(&ops); cq_.Pluck(&ops); /// status ignored @@ -222,9 +209,7 @@ class ClientReader final : public ClientReaderInterface { /// already received (if initial metadata is received, it can be then /// accessed through the \a ClientContext associated with this call). bool Read(R* msg) override { - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, - ::grpc::internal::CallOpRecvMessage> - ops; + CallOpSet> ops; if (!context_->initial_metadata_received_) { ops.RecvInitialMetadata(context_); } @@ -239,7 +224,7 @@ class ClientReader final : public ClientReaderInterface { /// The \a ClientContext associated with this call is updated with /// possible metadata received from the server. Status Finish() override { - ::grpc::internal::CallOpSet<::grpc::internal::CallOpClientRecvStatus> ops; + CallOpSet ops; Status status; ops.ClientRecvStatus(context_, &status); call_.PerformOps(&ops); @@ -250,48 +235,53 @@ class ClientReader final : public ClientReaderInterface { private: ClientContext* context_; CompletionQueue cq_; - ::grpc::internal::Call call_; + Call call_; +}; - /// Block to create a stream and write the initial metadata and \a request - /// out. Note that \a context will be used to fill in custom initial - /// metadata used to send to the server when starting the call. - template - ClientReader(::grpc::ChannelInterface* channel, - const ::grpc::internal::RpcMethod& method, - ClientContext* context, const W& request) - : context_(context), - cq_(grpc_completion_queue_attributes{ - GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, - GRPC_CQ_DEFAULT_POLLING}), // Pluckable cq - call_(channel->CreateCall(method, context, &cq_)) { - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, - ::grpc::internal::CallOpSendMessage, - ::grpc::internal::CallOpClientSendClose> - ops; - ops.SendInitialMetadata(context->send_initial_metadata_, - context->initial_metadata_flags()); - // TODO(ctiller): don't assert - GPR_CODEGEN_ASSERT(ops.SendMessage(request).ok()); - ops.ClientSendClose(); - call_.PerformOps(&ops); - cq_.Pluck(&ops); - } +/// Client-side interface for streaming writes of message type \a W. +template +class ClientWriterInterface : public ClientStreamingInterface, + public WriterInterface { + public: + /// Half close writing from the client. (signal that the stream of messages + /// coming from the clinet is complete). + /// Blocks until currently-pending writes are completed. + /// Thread safe with respect to \a ReaderInterface::Read operations only + /// + /// \return Whether the writes were successful. + virtual bool WritesDone() = 0; }; /// Synchronous (blocking) client-side API for doing client-streaming RPCs, /// where the outgoing message stream coming from the client has messages of /// type \a W. template -class ClientWriter final : public ClientWriterInterface { +class ClientWriter : public ClientWriterInterface { public: - struct internal { - template - static ClientWriter* Create(::grpc::ChannelInterface* channel, - const ::grpc::internal::RpcMethod& method, - ClientContext* context, R* response) { - return new ClientWriter(channel, method, context, response); + /// Block to create a stream (i.e. send request headers and other initial + /// metadata to the server). Note that \a context will be used to fill + /// in custom initial metadata. \a response will be filled in with the + /// single expected response message from the server upon a successful + /// call to the \a Finish method of this instance. + template + ClientWriter(ChannelInterface* channel, const RpcMethod& method, + ClientContext* context, R* response) + : context_(context), + cq_(grpc_completion_queue_attributes{ + GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, + GRPC_CQ_DEFAULT_POLLING}), // Pluckable cq + call_(channel->CreateCall(method, context, &cq_)) { + finish_ops_.RecvMessage(response); + finish_ops_.AllowNoMessage(); + + if (!context_->initial_metadata_corked_) { + CallOpSet ops; + ops.SendInitialMetadata(context->send_initial_metadata_, + context->initial_metadata_flags()); + call_.PerformOps(&ops); + cq_.Pluck(&ops); } - }; + } /// See the \a ClientStreamingInterface.WaitForInitialMetadata method for /// semantics. @@ -302,8 +292,7 @@ class ClientWriter final : public ClientWriterInterface { void WaitForInitialMetadata() { GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_); - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata> - ops; + CallOpSet ops; ops.RecvInitialMetadata(context_); call_.PerformOps(&ops); cq_.Pluck(&ops); // status ignored @@ -315,11 +304,10 @@ class ClientWriter final : public ClientWriterInterface { /// Side effect: /// Also sends initial metadata if not already sent (using the /// \a ClientContext associated with this call). - using ::grpc::internal::WriterInterface::Write; + using WriterInterface::Write; bool Write(const W& msg, WriteOptions options) override { - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, - ::grpc::internal::CallOpSendMessage, - ::grpc::internal::CallOpClientSendClose> + CallOpSet ops; if (options.is_last_message()) { @@ -340,7 +328,7 @@ class ClientWriter final : public ClientWriterInterface { } bool WritesDone() override { - ::grpc::internal::CallOpSet<::grpc::internal::CallOpClientSendClose> ops; + CallOpSet ops; ops.ClientSendClose(); call_.PerformOps(&ops); return cq_.Pluck(&ops); @@ -365,55 +353,61 @@ class ClientWriter final : public ClientWriterInterface { private: ClientContext* context_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, - ::grpc::internal::CallOpGenericRecvMessage, - ::grpc::internal::CallOpClientRecvStatus> + CallOpSet finish_ops_; CompletionQueue cq_; - ::grpc::internal::Call call_; + Call call_; +}; - /// Block to create a stream (i.e. send request headers and other initial - /// metadata to the server). Note that \a context will be used to fill - /// in custom initial metadata. \a response will be filled in with the - /// single expected response message from the server upon a successful - /// call to the \a Finish method of this instance. - template - ClientWriter(::grpc::ChannelInterface* channel, - const ::grpc::internal::RpcMethod& method, - ClientContext* context, R* response) +/// Client-side interface for bi-directional streaming with +/// client-to-server stream messages of type \a W and +/// server-to-client stream messages of type \a R. +template +class ClientReaderWriterInterface : public ClientStreamingInterface, + public WriterInterface, + public ReaderInterface { + public: + /// Block to wait for initial metadata from server. The received metadata + /// can only be accessed after this call returns. Should only be called before + /// the first read. Calling this method is optional, and if it is not called + /// the metadata will be available in ClientContext after the first read. + virtual void WaitForInitialMetadata() = 0; + + /// Half close writing from the client. (signal that the stream of messages + /// coming from the clinet is complete). + /// Blocks until currently-pending writes are completed. + /// Thread-safe with respect to \a ReaderInterface::Read + /// + /// \return Whether the writes were successful. + virtual bool WritesDone() = 0; +}; + +/// Synchronous (blocking) client-side API for bi-directional streaming RPCs, +/// where the outgoing message stream coming from the client has messages of +/// type \a W, and the incoming messages stream coming from the server has +/// messages of type \a R. +template +class ClientReaderWriter final : public ClientReaderWriterInterface { + public: + /// Block to create a stream and write the initial metadata and \a request + /// out. Note that \a context will be used to fill in custom initial metadata + /// used to send to the server when starting the call. + ClientReaderWriter(ChannelInterface* channel, const RpcMethod& method, + ClientContext* context) : context_(context), cq_(grpc_completion_queue_attributes{ GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, GRPC_CQ_DEFAULT_POLLING}), // Pluckable cq call_(channel->CreateCall(method, context, &cq_)) { - finish_ops_.RecvMessage(response); - finish_ops_.AllowNoMessage(); - if (!context_->initial_metadata_corked_) { - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata> - ops; + CallOpSet ops; ops.SendInitialMetadata(context->send_initial_metadata_, context->initial_metadata_flags()); call_.PerformOps(&ops); cq_.Pluck(&ops); } } -}; - -/// Synchronous (blocking) client-side API for bi-directional streaming RPCs, -/// where the outgoing message stream coming from the client has messages of -/// type \a W, and the incoming messages stream coming from the server has -/// messages of type \a R. -template -class ClientReaderWriter final : public ClientReaderWriterInterface { - public: - struct internal { - static ClientReaderWriter* Create(::grpc::ChannelInterface* channel, - const ::grpc::internal::RpcMethod& method, - ClientContext* context) { - return new ClientReaderWriter(channel, method, context); - } - }; /// Block waiting to read initial metadata from the server. /// This call is optional, but if it is used, it cannot be used concurrently @@ -424,8 +418,7 @@ class ClientReaderWriter final : public ClientReaderWriterInterface { void WaitForInitialMetadata() override { GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_); - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata> - ops; + CallOpSet ops; ops.RecvInitialMetadata(context_); call_.PerformOps(&ops); cq_.Pluck(&ops); // status ignored @@ -441,9 +434,7 @@ class ClientReaderWriter final : public ClientReaderWriterInterface { /// Also receives initial metadata if not already received (updates the \a /// ClientContext associated with this call in that case). bool Read(R* msg) override { - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, - ::grpc::internal::CallOpRecvMessage> - ops; + CallOpSet> ops; if (!context_->initial_metadata_received_) { ops.RecvInitialMetadata(context_); } @@ -457,11 +448,10 @@ class ClientReaderWriter final : public ClientReaderWriterInterface { /// Side effect: /// Also sends initial metadata if not already sent (using the /// \a ClientContext associated with this call to fill in values). - using ::grpc::internal::WriterInterface::Write; + using WriterInterface::Write; bool Write(const W& msg, WriteOptions options) override { - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, - ::grpc::internal::CallOpSendMessage, - ::grpc::internal::CallOpClientSendClose> + CallOpSet ops; if (options.is_last_message()) { @@ -482,7 +472,7 @@ class ClientReaderWriter final : public ClientReaderWriterInterface { } bool WritesDone() override { - ::grpc::internal::CallOpSet<::grpc::internal::CallOpClientSendClose> ops; + CallOpSet ops; ops.ClientSendClose(); call_.PerformOps(&ops); return cq_.Pluck(&ops); @@ -494,9 +484,7 @@ class ClientReaderWriter final : public ClientReaderWriterInterface { /// - the \a ClientContext associated with this call is updated with /// possible trailing metadata sent from the server. Status Finish() override { - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, - ::grpc::internal::CallOpClientRecvStatus> - ops; + CallOpSet ops; if (!context_->initial_metadata_received_) { ops.RecvInitialMetadata(context_); } @@ -510,61 +498,13 @@ class ClientReaderWriter final : public ClientReaderWriterInterface { private: ClientContext* context_; CompletionQueue cq_; - ::grpc::internal::Call call_; - - /// Block to create a stream and write the initial metadata and \a request - /// out. Note that \a context will be used to fill in custom initial metadata - /// used to send to the server when starting the call. - ClientReaderWriter(::grpc::ChannelInterface* channel, - const ::grpc::internal::RpcMethod& method, - ClientContext* context) - : context_(context), - cq_(grpc_completion_queue_attributes{ - GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, - GRPC_CQ_DEFAULT_POLLING}), // Pluckable cq - call_(channel->CreateCall(method, context, &cq_)) { - if (!context_->initial_metadata_corked_) { - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata> - ops; - ops.SendInitialMetadata(context->send_initial_metadata_, - context->initial_metadata_flags()); - call_.PerformOps(&ops); - cq_.Pluck(&ops); - } - } + Call call_; }; -namespace internal { -/// Common interface for all synchronous server side streaming. -class ServerStreamingInterface { - public: - virtual ~ServerStreamingInterface() {} - - /// Block to send initial metadata to client. - /// This call is optional, but if it is used, it cannot be used concurrently - /// with or after the \a Finish method. - /// - /// The initial metadata that will be sent to the client will be - /// taken from the \a ServerContext associated with the call. - virtual void SendInitialMetadata() = 0; -}; -} // namespace internal - /// Server-side interface for streaming reads of message of type \a R. template -class ServerReaderInterface : public internal::ServerStreamingInterface, - public internal::ReaderInterface {}; - -/// Server-side interface for streaming writes of message of type \a W. -template -class ServerWriterInterface : public internal::ServerStreamingInterface, - public internal::WriterInterface {}; - -/// Server-side interface for bi-directional streaming. -template -class ServerReaderWriterInterface : public internal::ServerStreamingInterface, - public internal::WriterInterface, - public internal::ReaderInterface {}; +class ServerReaderInterface : public ServerStreamingInterface, + public ReaderInterface {}; /// Synchronous (blocking) server-side API for doing client-streaming RPCs, /// where the incoming message stream coming from the client has messages of @@ -572,13 +512,15 @@ class ServerReaderWriterInterface : public internal::ServerStreamingInterface, template class ServerReader final : public ServerReaderInterface { public: + ServerReader(Call* call, ServerContext* ctx) : call_(call), ctx_(ctx) {} + /// See the \a ServerStreamingInterface.SendInitialMetadata method /// for semantics. Note that initial metadata will be affected by the /// \a ServerContext associated with this call. void SendInitialMetadata() override { GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); - internal::CallOpSet ops; + CallOpSet ops; ops.SendInitialMetadata(ctx_->initial_metadata_, ctx_->initial_metadata_flags()); if (ctx_->compression_level_set()) { @@ -595,29 +537,30 @@ class ServerReader final : public ServerReaderInterface { } bool Read(R* msg) override { - internal::CallOpSet> ops; + CallOpSet> ops; ops.RecvMessage(msg); call_->PerformOps(&ops); return call_->cq()->Pluck(&ops) && ops.got_message; } private: - internal::Call* const call_; + Call* const call_; ServerContext* const ctx_; - - template - friend class internal::ClientStreamingHandler; - - ServerReader(internal::Call* call, ServerContext* ctx) - : call_(call), ctx_(ctx) {} }; +/// Server-side interface for streaming writes of message of type \a W. +template +class ServerWriterInterface : public ServerStreamingInterface, + public WriterInterface {}; + /// Synchronous (blocking) server-side API for doing for doing a /// server-streaming RPCs, where the outgoing message stream coming from the /// server has messages of type \a W. template class ServerWriter final : public ServerWriterInterface { public: + ServerWriter(Call* call, ServerContext* ctx) : call_(call), ctx_(ctx) {} + /// See the \a ServerStreamingInterface.SendInitialMetadata method /// for semantics. /// Note that initial metadata will be affected by the @@ -625,7 +568,7 @@ class ServerWriter final : public ServerWriterInterface { void SendInitialMetadata() override { GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); - internal::CallOpSet ops; + CallOpSet ops; ops.SendInitialMetadata(ctx_->initial_metadata_, ctx_->initial_metadata_flags()); if (ctx_->compression_level_set()) { @@ -641,12 +584,11 @@ class ServerWriter final : public ServerWriterInterface { /// Side effect: /// Also sends initial metadata if not already sent (using the /// \a ClientContext associated with this call to fill in values). - using internal::WriterInterface::Write; + using WriterInterface::Write; bool Write(const W& msg, WriteOptions options) override { if (options.is_last_message()) { options.set_buffer_hint(); } - if (!ctx_->pending_ops_.SendMessage(msg, options).ok()) { return false; } @@ -671,16 +613,16 @@ class ServerWriter final : public ServerWriterInterface { } private: - internal::Call* const call_; + Call* const call_; ServerContext* const ctx_; - - template - friend class internal::ServerStreamingHandler; - - ServerWriter(internal::Call* call, ServerContext* ctx) - : call_(call), ctx_(ctx) {} }; +/// Server-side interface for bi-directional streaming. +template +class ServerReaderWriterInterface : public ServerStreamingInterface, + public WriterInterface, + public ReaderInterface {}; + /// Actual implementation of bi-directional streaming namespace internal { template @@ -746,7 +688,6 @@ class ServerReaderWriterBody final { Call* const call_; ServerContext* const ctx_; }; - } // namespace internal /// Synchronous (blocking) server-side API for a bidirectional @@ -756,6 +697,8 @@ class ServerReaderWriterBody final { template class ServerReaderWriter final : public ServerReaderWriterInterface { public: + ServerReaderWriter(Call* call, ServerContext* ctx) : body_(call, ctx) {} + /// See the \a ServerStreamingInterface.SendInitialMetadata method /// for semantics. Note that initial metadata will be affected by the /// \a ServerContext associated with this call. @@ -772,18 +715,13 @@ class ServerReaderWriter final : public ServerReaderWriterInterface { /// Side effect: /// Also sends initial metadata if not already sent (using the \a /// ServerContext associated with this call). - using internal::WriterInterface::Write; + using WriterInterface::Write; bool Write(const W& msg, WriteOptions options) override { return body_.Write(msg, options); } private: internal::ServerReaderWriterBody body_; - - friend class internal::TemplatedBidiStreamingHandler, - false>; - ServerReaderWriter(internal::Call* call, ServerContext* ctx) - : body_(call, ctx) {} }; /// A class to represent a flow-controlled unary call. This is something @@ -798,6 +736,9 @@ template class ServerUnaryStreamer final : public ServerReaderWriterInterface { public: + ServerUnaryStreamer(Call* call, ServerContext* ctx) + : body_(call, ctx), read_done_(false), write_done_(false) {} + /// Block to send initial metadata to client. /// Implicit input parameter: /// - the \a ServerContext associated with this call will be used for @@ -834,7 +775,7 @@ class ServerUnaryStreamer final /// \param options The WriteOptions affecting the write operation. /// /// \return \a true on success, \a false when the stream has been closed. - using internal::WriterInterface::Write; + using WriterInterface::Write; bool Write(const ResponseType& response, WriteOptions options) override { if (write_done_ || !read_done_) { return false; @@ -847,11 +788,6 @@ class ServerUnaryStreamer final internal::ServerReaderWriterBody body_; bool read_done_; bool write_done_; - - friend class internal::TemplatedBidiStreamingHandler< - ServerUnaryStreamer, true>; - ServerUnaryStreamer(internal::Call* call, ServerContext* ctx) - : body_(call, ctx), read_done_(false), write_done_(false) {} }; /// A class to represent a flow-controlled server-side streaming call. @@ -863,6 +799,9 @@ template class ServerSplitStreamer final : public ServerReaderWriterInterface { public: + ServerSplitStreamer(Call* call, ServerContext* ctx) + : body_(call, ctx), read_done_(false) {} + /// Block to send initial metadata to client. /// Implicit input parameter: /// - the \a ServerContext associated with this call will be used for @@ -899,7 +838,7 @@ class ServerSplitStreamer final /// \param options The WriteOptions affecting the write operation. /// /// \return \a true on success, \a false when the stream has been closed. - using internal::WriterInterface::Write; + using WriterInterface::Write; bool Write(const ResponseType& response, WriteOptions options) override { return read_done_ && body_.Write(response, options); } @@ -907,11 +846,6 @@ class ServerSplitStreamer final private: internal::ServerReaderWriterBody body_; bool read_done_; - - friend class internal::TemplatedBidiStreamingHandler< - ServerSplitStreamer, false>; - ServerSplitStreamer(internal::Call* call, ServerContext* ctx) - : body_(call, ctx), read_done_(false) {} }; } // namespace grpc diff --git a/include/grpc++/impl/codegen/time.h b/include/grpc++/impl/codegen/time.h index d464d6ea136..589deb4f03d 100644 --- a/include/grpc++/impl/codegen/time.h +++ b/include/grpc++/impl/codegen/time.h @@ -19,8 +19,6 @@ #ifndef GRPCXX_IMPL_CODEGEN_TIME_H #define GRPCXX_IMPL_CODEGEN_TIME_H -#include - #include #include @@ -61,6 +59,10 @@ class TimePoint { } // namespace grpc +#include + +#include + namespace grpc { // from and to should be absolute time. diff --git a/include/grpc++/server.h b/include/grpc++/server.h index 01c4a60d216..0a3aae8241c 100644 --- a/include/grpc++/server.h +++ b/include/grpc++/server.h @@ -175,8 +175,7 @@ class Server final : public ServerInterface, private GrpcLibraryCodegen { /// \param num_cqs How many completion queues does \a cqs hold. void Start(ServerCompletionQueue** cqs, size_t num_cqs) override; - void PerformOpsOnCall(internal::CallOpSetInterface* ops, - internal::Call* call) override; + void PerformOpsOnCall(CallOpSetInterface* ops, Call* call) override; void ShutdownInternal(gpr_timespec deadline) override; diff --git a/include/grpc++/server_builder.h b/include/grpc++/server_builder.h index 5bd53bd90f2..eafd63619d2 100644 --- a/include/grpc++/server_builder.h +++ b/include/grpc++/server_builder.h @@ -40,6 +40,7 @@ namespace grpc { class AsyncGenericService; class ResourceQuota; class CompletionQueue; +class RpcService; class Server; class ServerCompletionQueue; class ServerCredentials; diff --git a/src/compiler/cpp_generator.cc b/src/compiler/cpp_generator.cc index f8c6fda3403..b09bf996774 100644 --- a/src/compiler/cpp_generator.cc +++ b/src/compiler/cpp_generator.cc @@ -140,6 +140,7 @@ grpc::string GetHeaderIncludes(grpc_generator::File *file, printer->Print(vars, "namespace grpc {\n"); printer->Print(vars, "class CompletionQueue;\n"); printer->Print(vars, "class Channel;\n"); + printer->Print(vars, "class RpcService;\n"); printer->Print(vars, "class ServerCompletionQueue;\n"); printer->Print(vars, "class ServerContext;\n"); printer->Print(vars, "} // namespace grpc\n\n"); @@ -186,21 +187,19 @@ void PrintHeaderClientMethodInterfaces( } else if (ClientOnlyStreaming(method)) { printer->Print( *vars, - "std::unique_ptr< ::grpc::ClientWriterInterface< " - "$Request$>>" + "std::unique_ptr< ::grpc::ClientWriterInterface< $Request$>>" " $Method$(" "::grpc::ClientContext* context, $Response$* response) {\n"); printer->Indent(); - printer->Print(*vars, - "return std::unique_ptr< " - "::grpc::ClientWriterInterface< $Request$>>" - "($Method$Raw(context, response));\n"); + printer->Print( + *vars, + "return std::unique_ptr< ::grpc::ClientWriterInterface< $Request$>>" + "($Method$Raw(context, response));\n"); printer->Outdent(); printer->Print("}\n"); printer->Print( *vars, - "std::unique_ptr< ::grpc::ClientAsyncWriterInterface< " - "$Request$>>" + "std::unique_ptr< ::grpc::ClientAsyncWriterInterface< $Request$>>" " Async$Method$(::grpc::ClientContext* context, $Response$* " "response, " "::grpc::CompletionQueue* cq, void* tag) {\n"); @@ -214,21 +213,19 @@ void PrintHeaderClientMethodInterfaces( } else if (ServerOnlyStreaming(method)) { printer->Print( *vars, - "std::unique_ptr< ::grpc::ClientReaderInterface< " - "$Response$>>" + "std::unique_ptr< ::grpc::ClientReaderInterface< $Response$>>" " $Method$(::grpc::ClientContext* context, const $Request$& request)" " {\n"); printer->Indent(); - printer->Print(*vars, - "return std::unique_ptr< " - "::grpc::ClientReaderInterface< $Response$>>" - "($Method$Raw(context, request));\n"); + printer->Print( + *vars, + "return std::unique_ptr< ::grpc::ClientReaderInterface< $Response$>>" + "($Method$Raw(context, request));\n"); printer->Outdent(); printer->Print("}\n"); printer->Print( *vars, - "std::unique_ptr< ::grpc::ClientAsyncReaderInterface< " - "$Response$>> " + "std::unique_ptr< ::grpc::ClientAsyncReaderInterface< $Response$>> " "Async$Method$(" "::grpc::ClientContext* context, const $Request$& request, " "::grpc::CompletionQueue* cq, void* tag) {\n"); @@ -245,37 +242,36 @@ void PrintHeaderClientMethodInterfaces( "$Request$, $Response$>> " "$Method$(::grpc::ClientContext* context) {\n"); printer->Indent(); - printer->Print(*vars, - "return std::unique_ptr< " - "::grpc::ClientReaderWriterInterface< " - "$Request$, $Response$>>(" - "$Method$Raw(context));\n"); + printer->Print( + *vars, + "return std::unique_ptr< " + "::grpc::ClientReaderWriterInterface< $Request$, $Response$>>(" + "$Method$Raw(context));\n"); printer->Outdent(); printer->Print("}\n"); - printer->Print(*vars, - "std::unique_ptr< " - "::grpc::ClientAsyncReaderWriterInterface< " - "$Request$, $Response$>> " - "Async$Method$(::grpc::ClientContext* context, " - "::grpc::CompletionQueue* cq, void* tag) {\n"); + printer->Print( + *vars, + "std::unique_ptr< " + "::grpc::ClientAsyncReaderWriterInterface< $Request$, $Response$>> " + "Async$Method$(::grpc::ClientContext* context, " + "::grpc::CompletionQueue* cq, void* tag) {\n"); printer->Indent(); - printer->Print(*vars, - "return std::unique_ptr< " - "::grpc::ClientAsyncReaderWriterInterface< " - "$Request$, $Response$>>(" - "Async$Method$Raw(context, cq, tag));\n"); + printer->Print( + *vars, + "return std::unique_ptr< " + "::grpc::ClientAsyncReaderWriterInterface< $Request$, $Response$>>(" + "Async$Method$Raw(context, cq, tag));\n"); printer->Outdent(); printer->Print("}\n"); } } else { if (method->NoStreaming()) { - printer->Print(*vars, - "virtual " - "::grpc::ClientAsyncResponseReaderInterface< " - "$Response$>* " - "Async$Method$Raw(::grpc::ClientContext* context, " - "const $Request$& request, " - "::grpc::CompletionQueue* cq) = 0;\n"); + printer->Print( + *vars, + "virtual ::grpc::ClientAsyncResponseReaderInterface< $Response$>* " + "Async$Method$Raw(::grpc::ClientContext* context, " + "const $Request$& request, " + "::grpc::CompletionQueue* cq) = 0;\n"); } else if (ClientOnlyStreaming(method)) { printer->Print( *vars, @@ -290,8 +286,7 @@ void PrintHeaderClientMethodInterfaces( } else if (ServerOnlyStreaming(method)) { printer->Print( *vars, - "virtual ::grpc::ClientReaderInterface< $Response$>* " - "$Method$Raw(" + "virtual ::grpc::ClientReaderInterface< $Response$>* $Method$Raw(" "::grpc::ClientContext* context, const $Request$& request) = 0;\n"); printer->Print( *vars, @@ -456,8 +451,7 @@ void PrintHeaderClientMethodData(grpc_generator::Printer *printer, const grpc_generator::Method *method, std::map *vars) { (*vars)["Method"] = method->name(); - printer->Print(*vars, - "const ::grpc::internal::RpcMethod rpcmethod_$Method$_;\n"); + printer->Print(*vars, "const ::grpc::RpcMethod rpcmethod_$Method$_;\n"); } void PrintHeaderServerMethodSync(grpc_generator::Printer *printer, @@ -629,7 +623,7 @@ void PrintHeaderServerMethodStreamedUnary( printer->Print(*vars, "WithStreamedUnaryMethod_$Method$() {\n" " ::grpc::Service::MarkMethodStreamed($Idx$,\n" - " new ::grpc::internal::StreamedUnaryHandler< $Request$, " + " new ::grpc::StreamedUnaryHandler< $Request$, " "$Response$>(std::bind" "(&WithStreamedUnaryMethod_$Method$::" "Streamed$Method$, this, std::placeholders::_1, " @@ -677,16 +671,15 @@ void PrintHeaderServerMethodSplitStreaming( "{}\n"); printer->Print(" public:\n"); printer->Indent(); - printer->Print( - *vars, - "WithSplitStreamingMethod_$Method$() {\n" - " ::grpc::Service::MarkMethodStreamed($Idx$,\n" - " new ::grpc::internal::SplitServerStreamingHandler< $Request$, " - "$Response$>(std::bind" - "(&WithSplitStreamingMethod_$Method$::" - "Streamed$Method$, this, std::placeholders::_1, " - "std::placeholders::_2)));\n" - "}\n"); + printer->Print(*vars, + "WithSplitStreamingMethod_$Method$() {\n" + " ::grpc::Service::MarkMethodStreamed($Idx$,\n" + " new ::grpc::SplitServerStreamingHandler< $Request$, " + "$Response$>(std::bind" + "(&WithSplitStreamingMethod_$Method$::" + "Streamed$Method$, this, std::placeholders::_1, " + "std::placeholders::_2)));\n" + "}\n"); printer->Print(*vars, "~WithSplitStreamingMethod_$Method$() override {\n" " BaseClassMustBeDerivedFromService(this);\n" @@ -826,8 +819,7 @@ void PrintHeaderService(grpc_generator::Printer *printer, " {\n public:\n"); printer->Indent(); printer->Print( - "Stub(const std::shared_ptr< ::grpc::ChannelInterface>& " - "channel);\n"); + "Stub(const std::shared_ptr< ::grpc::ChannelInterface>& channel);\n"); for (int i = 0; i < service->method_count(); ++i) { PrintHeaderClientMethod(printer, service->method(i).get(), vars, true); } @@ -1090,12 +1082,11 @@ void PrintSourceClientMethod(grpc_generator::Printer *printer, "::grpc::Status $ns$$Service$::Stub::$Method$(" "::grpc::ClientContext* context, " "const $Request$& request, $Response$* response) {\n"); - printer->Print( - *vars, - " return ::grpc::internal::BlockingUnaryCall(channel_.get(), " - "rpcmethod_$Method$_, " - "context, request, response);\n" - "}\n\n"); + printer->Print(*vars, + " return ::grpc::BlockingUnaryCall(channel_.get(), " + "rpcmethod_$Method$_, " + "context, request, response);\n" + "}\n\n"); printer->Print( *vars, "::grpc::ClientAsyncResponseReader< $Response$>* " @@ -1104,8 +1095,7 @@ void PrintSourceClientMethod(grpc_generator::Printer *printer, "::grpc::CompletionQueue* cq) {\n"); printer->Print(*vars, " return " - "::grpc::ClientAsyncResponseReader< $Response$>::" - "internal::Create(" + "::grpc::ClientAsyncResponseReader< $Response$>::Create(" "channel_.get(), cq, " "rpcmethod_$Method$_, " "context, request);\n" @@ -1115,21 +1105,19 @@ void PrintSourceClientMethod(grpc_generator::Printer *printer, "::grpc::ClientWriter< $Request$>* " "$ns$$Service$::Stub::$Method$Raw(" "::grpc::ClientContext* context, $Response$* response) {\n"); - printer->Print( - *vars, - " return ::grpc::ClientWriter< $Request$>::internal::Create(" - "channel_.get(), " - "rpcmethod_$Method$_, " - "context, response);\n" - "}\n\n"); + printer->Print(*vars, + " return new ::grpc::ClientWriter< $Request$>(" + "channel_.get(), " + "rpcmethod_$Method$_, " + "context, response);\n" + "}\n\n"); printer->Print(*vars, "::grpc::ClientAsyncWriter< $Request$>* " "$ns$$Service$::Stub::Async$Method$Raw(" "::grpc::ClientContext* context, $Response$* response, " "::grpc::CompletionQueue* cq, void* tag) {\n"); printer->Print(*vars, - " return ::grpc::ClientAsyncWriter< $Request$>::" - "internal::Create(" + " return ::grpc::ClientAsyncWriter< $Request$>::Create(" "channel_.get(), cq, " "rpcmethod_$Method$_, " "context, response, tag);\n" @@ -1140,21 +1128,19 @@ void PrintSourceClientMethod(grpc_generator::Printer *printer, "::grpc::ClientReader< $Response$>* " "$ns$$Service$::Stub::$Method$Raw(" "::grpc::ClientContext* context, const $Request$& request) {\n"); - printer->Print( - *vars, - " return ::grpc::ClientReader< $Response$>::internal::Create(" - "channel_.get(), " - "rpcmethod_$Method$_, " - "context, request);\n" - "}\n\n"); + printer->Print(*vars, + " return new ::grpc::ClientReader< $Response$>(" + "channel_.get(), " + "rpcmethod_$Method$_, " + "context, request);\n" + "}\n\n"); printer->Print(*vars, "::grpc::ClientAsyncReader< $Response$>* " "$ns$$Service$::Stub::Async$Method$Raw(" "::grpc::ClientContext* context, const $Request$& request, " "::grpc::CompletionQueue* cq, void* tag) {\n"); printer->Print(*vars, - " return ::grpc::ClientAsyncReader< $Response$>::" - "internal::Create(" + " return ::grpc::ClientAsyncReader< $Response$>::Create(" "channel_.get(), cq, " "rpcmethod_$Method$_, " "context, request, tag);\n" @@ -1165,8 +1151,8 @@ void PrintSourceClientMethod(grpc_generator::Printer *printer, "::grpc::ClientReaderWriter< $Request$, $Response$>* " "$ns$$Service$::Stub::$Method$Raw(::grpc::ClientContext* context) {\n"); printer->Print(*vars, - " return ::grpc::ClientReaderWriter< " - "$Request$, $Response$>::internal::Create(" + " return new ::grpc::ClientReaderWriter< " + "$Request$, $Response$>(" "channel_.get(), " "rpcmethod_$Method$_, " "context);\n" @@ -1176,14 +1162,14 @@ void PrintSourceClientMethod(grpc_generator::Printer *printer, "::grpc::ClientAsyncReaderWriter< $Request$, $Response$>* " "$ns$$Service$::Stub::Async$Method$Raw(::grpc::ClientContext* context, " "::grpc::CompletionQueue* cq, void* tag) {\n"); - printer->Print(*vars, - " return " - "::grpc::ClientAsyncReaderWriter< $Request$, $Response$>::" - "internal::Create(" - "channel_.get(), cq, " - "rpcmethod_$Method$_, " - "context, tag);\n" - "}\n\n"); + printer->Print( + *vars, + " return " + "::grpc::ClientAsyncReaderWriter< $Request$, $Response$>::Create(" + "channel_.get(), cq, " + "rpcmethod_$Method$_, " + "context, tag);\n" + "}\n\n"); } } @@ -1293,7 +1279,7 @@ void PrintSourceService(grpc_generator::Printer *printer, printer->Print(*vars, ", rpcmethod_$Method$_(" "$prefix$$Service$_method_names[$Idx$], " - "::grpc::internal::RpcMethod::$StreamingType$, " + "::grpc::RpcMethod::$StreamingType$, " "channel" ")\n"); } @@ -1316,38 +1302,38 @@ void PrintSourceService(grpc_generator::Printer *printer, if (method->NoStreaming()) { printer->Print( *vars, - "AddMethod(new ::grpc::internal::RpcServiceMethod(\n" + "AddMethod(new ::grpc::RpcServiceMethod(\n" " $prefix$$Service$_method_names[$Idx$],\n" - " ::grpc::internal::RpcMethod::NORMAL_RPC,\n" - " new ::grpc::internal::RpcMethodHandler< $ns$$Service$::Service, " + " ::grpc::RpcMethod::NORMAL_RPC,\n" + " new ::grpc::RpcMethodHandler< $ns$$Service$::Service, " "$Request$, " "$Response$>(\n" " std::mem_fn(&$ns$$Service$::Service::$Method$), this)));\n"); } else if (ClientOnlyStreaming(method.get())) { printer->Print( *vars, - "AddMethod(new ::grpc::internal::RpcServiceMethod(\n" + "AddMethod(new ::grpc::RpcServiceMethod(\n" " $prefix$$Service$_method_names[$Idx$],\n" - " ::grpc::internal::RpcMethod::CLIENT_STREAMING,\n" - " new ::grpc::internal::ClientStreamingHandler< " + " ::grpc::RpcMethod::CLIENT_STREAMING,\n" + " new ::grpc::ClientStreamingHandler< " "$ns$$Service$::Service, $Request$, $Response$>(\n" " std::mem_fn(&$ns$$Service$::Service::$Method$), this)));\n"); } else if (ServerOnlyStreaming(method.get())) { printer->Print( *vars, - "AddMethod(new ::grpc::internal::RpcServiceMethod(\n" + "AddMethod(new ::grpc::RpcServiceMethod(\n" " $prefix$$Service$_method_names[$Idx$],\n" - " ::grpc::internal::RpcMethod::SERVER_STREAMING,\n" - " new ::grpc::internal::ServerStreamingHandler< " + " ::grpc::RpcMethod::SERVER_STREAMING,\n" + " new ::grpc::ServerStreamingHandler< " "$ns$$Service$::Service, $Request$, $Response$>(\n" " std::mem_fn(&$ns$$Service$::Service::$Method$), this)));\n"); } else if (method->BidiStreaming()) { printer->Print( *vars, - "AddMethod(new ::grpc::internal::RpcServiceMethod(\n" + "AddMethod(new ::grpc::RpcServiceMethod(\n" " $prefix$$Service$_method_names[$Idx$],\n" - " ::grpc::internal::RpcMethod::BIDI_STREAMING,\n" - " new ::grpc::internal::BidiStreamingHandler< " + " ::grpc::RpcMethod::BIDI_STREAMING,\n" + " new ::grpc::BidiStreamingHandler< " "$ns$$Service$::Service, $Request$, $Response$>(\n" " std::mem_fn(&$ns$$Service$::Service::$Method$), this)));\n"); } @@ -1515,8 +1501,7 @@ void PrintMockClientMethods(grpc_generator::Printer *printer, printer->Print( *vars, "MOCK_METHOD3(Async$Method$Raw, " - "::grpc::ClientAsyncReaderWriterInterface<$Request$, " - "$Response$>*" + "::grpc::ClientAsyncReaderWriterInterface<$Request$, $Response$>*" "(::grpc::ClientContext* context, ::grpc::CompletionQueue* cq, " "void* tag));\n"); } diff --git a/src/cpp/client/channel_cc.cc b/src/cpp/client/channel_cc.cc index 038eb32e04b..f2d9bb07c95 100644 --- a/src/cpp/client/channel_cc.cc +++ b/src/cpp/client/channel_cc.cc @@ -76,9 +76,8 @@ grpc::string Channel::GetServiceConfigJSON() const { &channel_info.service_config_json); } -internal::Call Channel::CreateCall(const internal::RpcMethod& method, - ClientContext* context, - CompletionQueue* cq) { +Call Channel::CreateCall(const RpcMethod& method, ClientContext* context, + CompletionQueue* cq) { const bool kRegistered = method.channel_tag() && context->authority().empty(); grpc_call* c_call = NULL; if (kRegistered) { @@ -110,11 +109,10 @@ internal::Call Channel::CreateCall(const internal::RpcMethod& method, } grpc_census_call_set_context(c_call, context->census_context()); context->set_call(c_call, shared_from_this()); - return internal::Call(c_call, this, cq); + return Call(c_call, this, cq); } -void Channel::PerformOpsOnCall(internal::CallOpSetInterface* ops, - internal::Call* call) { +void Channel::PerformOpsOnCall(CallOpSetInterface* ops, Call* call) { static const size_t MAX_OPS = 8; size_t nops = 0; grpc_op cops[MAX_OPS]; @@ -133,7 +131,7 @@ grpc_connectivity_state Channel::GetState(bool try_to_connect) { } namespace { -class TagSaver final : public internal::CompletionQueueTag { +class TagSaver final : public CompletionQueueTag { public: explicit TagSaver(void* tag) : tag_(tag) {} ~TagSaver() override {} diff --git a/src/cpp/client/generic_stub.cc b/src/cpp/client/generic_stub.cc index e65cb9903f5..66b1ef0e39c 100644 --- a/src/cpp/client/generic_stub.cc +++ b/src/cpp/client/generic_stub.cc @@ -27,11 +27,9 @@ std::unique_ptr GenericStub::Call( ClientContext* context, const grpc::string& method, CompletionQueue* cq, void* tag) { return std::unique_ptr( - GenericClientAsyncReaderWriter::internal::Create( + GenericClientAsyncReaderWriter::Create( channel_.get(), cq, - internal::RpcMethod(method.c_str(), - internal::RpcMethod::BIDI_STREAMING), - context, tag)); + RpcMethod(method.c_str(), RpcMethod::BIDI_STREAMING), context, tag)); } } // namespace grpc diff --git a/src/cpp/common/completion_queue_cc.cc b/src/cpp/common/completion_queue_cc.cc index 000a03277b0..f34b0f3d583 100644 --- a/src/cpp/common/completion_queue_cc.cc +++ b/src/cpp/common/completion_queue_cc.cc @@ -60,7 +60,7 @@ CompletionQueue::NextStatus CompletionQueue::AsyncNextInternal( case GRPC_QUEUE_SHUTDOWN: return SHUTDOWN; case GRPC_OP_COMPLETE: - auto cq_tag = static_cast(ev.tag); + auto cq_tag = static_cast(ev.tag); *ok = ev.success != 0; *tag = cq_tag; if (cq_tag->FinalizeResult(tag, ok)) { diff --git a/src/cpp/server/health/default_health_check_service.cc b/src/cpp/server/health/default_health_check_service.cc index fc7feb79fe4..815b6070320 100644 --- a/src/cpp/server/health/default_health_check_service.cc +++ b/src/cpp/server/health/default_health_check_service.cc @@ -36,12 +36,11 @@ const char kHealthCheckMethodName[] = "/grpc.health.v1.Health/Check"; DefaultHealthCheckService::HealthCheckServiceImpl::HealthCheckServiceImpl( DefaultHealthCheckService* service) : service_(service), method_(nullptr) { - internal::MethodHandler* handler = - new internal::RpcMethodHandler( + MethodHandler* handler = + new RpcMethodHandler( std::mem_fn(&HealthCheckServiceImpl::Check), this); - method_ = new internal::RpcServiceMethod( - kHealthCheckMethodName, internal::RpcMethod::NORMAL_RPC, handler); + method_ = new RpcServiceMethod(kHealthCheckMethodName, RpcMethod::NORMAL_RPC, + handler); AddMethod(method_); } diff --git a/src/cpp/server/health/default_health_check_service.h b/src/cpp/server/health/default_health_check_service.h index 99d6680c501..09d5cebe98b 100644 --- a/src/cpp/server/health/default_health_check_service.h +++ b/src/cpp/server/health/default_health_check_service.h @@ -41,7 +41,7 @@ class DefaultHealthCheckService final : public HealthCheckServiceInterface { private: const DefaultHealthCheckService* const service_; - internal::RpcServiceMethod* method_; + RpcServiceMethod* method_; }; DefaultHealthCheckService(); diff --git a/src/cpp/server/server_cc.cc b/src/cpp/server/server_cc.cc index 60e067d89dd..92bacbe0618 100644 --- a/src/cpp/server/server_cc.cc +++ b/src/cpp/server/server_cc.cc @@ -88,8 +88,7 @@ class Server::UnimplementedAsyncRequest final ServerCompletionQueue* const cq_; }; -typedef internal::SneakyCallOpSet +typedef SneakyCallOpSet UnimplementedAsyncResponseOp; class Server::UnimplementedAsyncResponse final : public UnimplementedAsyncResponseOp { @@ -107,12 +106,12 @@ class Server::UnimplementedAsyncResponse final UnimplementedAsyncRequest* const request_; }; -class ShutdownTag : public internal::CompletionQueueTag { +class ShutdownTag : public CompletionQueueTag { public: bool FinalizeResult(void** tag, bool* status) { return false; } }; -class DummyTag : public internal::CompletionQueueTag { +class DummyTag : public CompletionQueueTag { public: bool FinalizeResult(void** tag, bool* status) { *status = true; @@ -120,15 +119,15 @@ class DummyTag : public internal::CompletionQueueTag { } }; -class Server::SyncRequest final : public internal::CompletionQueueTag { +class Server::SyncRequest final : public CompletionQueueTag { public: - SyncRequest(internal::RpcServiceMethod* method, void* tag) + SyncRequest(RpcServiceMethod* method, void* tag) : method_(method), tag_(tag), in_flight_(false), - has_request_payload_( - method->method_type() == internal::RpcMethod::NORMAL_RPC || - method->method_type() == internal::RpcMethod::SERVER_STREAMING), + has_request_payload_(method->method_type() == RpcMethod::NORMAL_RPC || + method->method_type() == + RpcMethod::SERVER_STREAMING), call_details_(nullptr), cq_(nullptr) { grpc_metadata_array_init(&request_metadata_); @@ -205,14 +204,14 @@ class Server::SyncRequest final : public internal::CompletionQueueTag { void Run(std::shared_ptr global_callbacks) { ctx_.BeginCompletionOp(&call_); global_callbacks->PreSynchronousRequest(&ctx_); - method_->handler()->RunHandler(internal::MethodHandler::HandlerParameter( - &call_, &ctx_, request_payload_)); + method_->handler()->RunHandler( + MethodHandler::HandlerParameter(&call_, &ctx_, request_payload_)); global_callbacks->PostSynchronousRequest(&ctx_); request_payload_ = nullptr; cq_.Shutdown(); - internal::CompletionQueueTag* op_tag = ctx_.GetCompletionOpTag(); + CompletionQueueTag* op_tag = ctx_.GetCompletionOpTag(); cq_.TryPluck(op_tag, gpr_inf_future(GPR_CLOCK_REALTIME)); /* Ensure the cq_ is shutdown */ @@ -222,15 +221,15 @@ class Server::SyncRequest final : public internal::CompletionQueueTag { private: CompletionQueue cq_; - internal::Call call_; + Call call_; ServerContext ctx_; const bool has_request_payload_; grpc_byte_buffer* request_payload_; - internal::RpcServiceMethod* const method_; + RpcServiceMethod* const method_; }; private: - internal::RpcServiceMethod* const method_; + RpcServiceMethod* const method_; void* const tag_; bool in_flight_; const bool has_request_payload_; @@ -303,15 +302,14 @@ class Server::SyncRequestThreadManager : public ThreadManager { // object } - void AddSyncMethod(internal::RpcServiceMethod* method, void* tag) { + void AddSyncMethod(RpcServiceMethod* method, void* tag) { sync_requests_.emplace_back(new SyncRequest(method, tag)); } void AddUnknownSyncMethod() { if (!sync_requests_.empty()) { - unknown_method_.reset(new internal::RpcServiceMethod( - "unknown", internal::RpcMethod::BIDI_STREAMING, - new internal::UnknownMethodHandler)); + unknown_method_.reset(new RpcServiceMethod( + "unknown", RpcMethod::BIDI_STREAMING, new UnknownMethodHandler)); sync_requests_.emplace_back( new SyncRequest(unknown_method_.get(), nullptr)); } @@ -348,8 +346,8 @@ class Server::SyncRequestThreadManager : public ThreadManager { CompletionQueue* server_cq_; int cq_timeout_msec_; std::vector> sync_requests_; - std::unique_ptr unknown_method_; - std::unique_ptr health_check_; + std::unique_ptr unknown_method_; + std::unique_ptr health_check_; std::shared_ptr global_callbacks_; }; @@ -432,13 +430,13 @@ std::shared_ptr Server::InProcessChannel( } static grpc_server_register_method_payload_handling PayloadHandlingForMethod( - internal::RpcServiceMethod* method) { + RpcServiceMethod* method) { switch (method->method_type()) { - case internal::RpcMethod::NORMAL_RPC: - case internal::RpcMethod::SERVER_STREAMING: + case RpcMethod::NORMAL_RPC: + case RpcMethod::SERVER_STREAMING: return GRPC_SRM_PAYLOAD_READ_INITIAL_BYTE_BUFFER; - case internal::RpcMethod::CLIENT_STREAMING: - case internal::RpcMethod::BIDI_STREAMING: + case RpcMethod::CLIENT_STREAMING: + case RpcMethod::BIDI_STREAMING: return GRPC_SRM_PAYLOAD_NONE; } GPR_UNREACHABLE_CODE(return GRPC_SRM_PAYLOAD_NONE;); @@ -459,7 +457,7 @@ bool Server::RegisterService(const grpc::string* host, Service* service) { continue; } - internal::RpcServiceMethod* method = it->get(); + RpcServiceMethod* method = it->get(); void* tag = grpc_server_register_method( server_, method->name(), host ? host->c_str() : nullptr, PayloadHandlingForMethod(method), 0); @@ -599,8 +597,7 @@ void Server::Wait() { } } -void Server::PerformOpsOnCall(internal::CallOpSetInterface* ops, - internal::Call* call) { +void Server::PerformOpsOnCall(CallOpSetInterface* ops, Call* call) { static const size_t MAX_OPS = 8; size_t nops = 0; grpc_op cops[MAX_OPS]; @@ -611,8 +608,8 @@ void Server::PerformOpsOnCall(internal::CallOpSetInterface* ops, ServerInterface::BaseAsyncRequest::BaseAsyncRequest( ServerInterface* server, ServerContext* context, - internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, - void* tag, bool delete_on_finalize) + ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, void* tag, + bool delete_on_finalize) : server_(server), context_(context), stream_(stream), @@ -634,8 +631,7 @@ bool ServerInterface::BaseAsyncRequest::FinalizeResult(void** tag, } context_->set_call(call_); context_->cq_ = call_cq_; - internal::Call call(call_, server_, call_cq_, - server_->max_receive_message_size()); + Call call(call_, server_, call_cq_, server_->max_receive_message_size()); if (*status && call_) { context_->BeginCompletionOp(&call); } @@ -650,8 +646,7 @@ bool ServerInterface::BaseAsyncRequest::FinalizeResult(void** tag, ServerInterface::RegisteredAsyncRequest::RegisteredAsyncRequest( ServerInterface* server, ServerContext* context, - internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, - void* tag) + ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, void* tag) : BaseAsyncRequest(server, context, stream, call_cq, tag, true) {} void ServerInterface::RegisteredAsyncRequest::IssueRequest( @@ -665,7 +660,7 @@ void ServerInterface::RegisteredAsyncRequest::IssueRequest( ServerInterface::GenericAsyncRequest::GenericAsyncRequest( ServerInterface* server, GenericServerContext* context, - internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, + ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, ServerCompletionQueue* notification_cq, void* tag, bool delete_on_finalize) : BaseAsyncRequest(server, context, stream, call_cq, tag, delete_on_finalize) { @@ -707,7 +702,7 @@ Server::UnimplementedAsyncResponse::UnimplementedAsyncResponse( UnimplementedAsyncRequest* request) : request_(request) { Status status(StatusCode::UNIMPLEMENTED, ""); - internal::UnknownMethodHandler::FillOps(request_->context(), this); + UnknownMethodHandler::FillOps(request_->context(), this); request_->stream()->call_.PerformOps(this); } diff --git a/src/cpp/server/server_context.cc b/src/cpp/server/server_context.cc index 2e55ffbac43..4913682f1d1 100644 --- a/src/cpp/server/server_context.cc +++ b/src/cpp/server/server_context.cc @@ -37,7 +37,7 @@ namespace grpc { // CompletionOp -class ServerContext::CompletionOp final : public internal::CallOpSetInterface { +class ServerContext::CompletionOp final : public CallOpSetInterface { public: // initial refs: one in the server context, one in the cq CompletionOp() @@ -146,7 +146,7 @@ ServerContext::~ServerContext() { } } -void ServerContext::BeginCompletionOp(internal::Call* call) { +void ServerContext::BeginCompletionOp(Call* call) { GPR_ASSERT(!completion_op_); completion_op_ = new CompletionOp(); if (has_notify_when_done_tag_) { @@ -155,8 +155,8 @@ void ServerContext::BeginCompletionOp(internal::Call* call) { call->PerformOps(completion_op_); } -internal::CompletionQueueTag* ServerContext::GetCompletionOpTag() { - return static_cast(completion_op_); +CompletionQueueTag* ServerContext::GetCompletionOpTag() { + return static_cast(completion_op_); } void ServerContext::AddInitialMetadata(const grpc::string& key, diff --git a/test/cpp/codegen/compiler_test_golden b/test/cpp/codegen/compiler_test_golden index f8c768831ed..b43c27f3f77 100644 --- a/test/cpp/codegen/compiler_test_golden +++ b/test/cpp/codegen/compiler_test_golden @@ -39,6 +39,7 @@ namespace grpc { class CompletionQueue; class Channel; +class RpcService; class ServerCompletionQueue; class ServerContext; } // namespace grpc @@ -136,10 +137,10 @@ class ServiceA final { ::grpc::ClientAsyncReader< ::grpc::testing::Response>* AsyncMethodA3Raw(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq, void* tag) override; ::grpc::ClientReaderWriter< ::grpc::testing::Request, ::grpc::testing::Response>* MethodA4Raw(::grpc::ClientContext* context) override; ::grpc::ClientAsyncReaderWriter< ::grpc::testing::Request, ::grpc::testing::Response>* AsyncMethodA4Raw(::grpc::ClientContext* context, ::grpc::CompletionQueue* cq, void* tag) override; - const ::grpc::internal::RpcMethod rpcmethod_MethodA1_; - const ::grpc::internal::RpcMethod rpcmethod_MethodA2_; - const ::grpc::internal::RpcMethod rpcmethod_MethodA3_; - const ::grpc::internal::RpcMethod rpcmethod_MethodA4_; + const ::grpc::RpcMethod rpcmethod_MethodA1_; + const ::grpc::RpcMethod rpcmethod_MethodA2_; + const ::grpc::RpcMethod rpcmethod_MethodA3_; + const ::grpc::RpcMethod rpcmethod_MethodA4_; }; static std::unique_ptr NewStub(const std::shared_ptr< ::grpc::ChannelInterface>& channel, const ::grpc::StubOptions& options = ::grpc::StubOptions()); @@ -319,7 +320,7 @@ class ServiceA final { public: WithStreamedUnaryMethod_MethodA1() { ::grpc::Service::MarkMethodStreamed(0, - new ::grpc::internal::StreamedUnaryHandler< ::grpc::testing::Request, ::grpc::testing::Response>(std::bind(&WithStreamedUnaryMethod_MethodA1::StreamedMethodA1, this, std::placeholders::_1, std::placeholders::_2))); + new ::grpc::StreamedUnaryHandler< ::grpc::testing::Request, ::grpc::testing::Response>(std::bind(&WithStreamedUnaryMethod_MethodA1::StreamedMethodA1, this, std::placeholders::_1, std::placeholders::_2))); } ~WithStreamedUnaryMethod_MethodA1() override { BaseClassMustBeDerivedFromService(this); @@ -340,7 +341,7 @@ class ServiceA final { public: WithSplitStreamingMethod_MethodA3() { ::grpc::Service::MarkMethodStreamed(2, - new ::grpc::internal::SplitServerStreamingHandler< ::grpc::testing::Request, ::grpc::testing::Response>(std::bind(&WithSplitStreamingMethod_MethodA3::StreamedMethodA3, this, std::placeholders::_1, std::placeholders::_2))); + new ::grpc::SplitServerStreamingHandler< ::grpc::testing::Request, ::grpc::testing::Response>(std::bind(&WithSplitStreamingMethod_MethodA3::StreamedMethodA3, this, std::placeholders::_1, std::placeholders::_2))); } ~WithSplitStreamingMethod_MethodA3() override { BaseClassMustBeDerivedFromService(this); @@ -386,7 +387,7 @@ class ServiceB final { private: std::shared_ptr< ::grpc::ChannelInterface> channel_; ::grpc::ClientAsyncResponseReader< ::grpc::testing::Response>* AsyncMethodB1Raw(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq) override; - const ::grpc::internal::RpcMethod rpcmethod_MethodB1_; + const ::grpc::RpcMethod rpcmethod_MethodB1_; }; static std::unique_ptr NewStub(const std::shared_ptr< ::grpc::ChannelInterface>& channel, const ::grpc::StubOptions& options = ::grpc::StubOptions()); @@ -443,7 +444,7 @@ class ServiceB final { public: WithStreamedUnaryMethod_MethodB1() { ::grpc::Service::MarkMethodStreamed(0, - new ::grpc::internal::StreamedUnaryHandler< ::grpc::testing::Request, ::grpc::testing::Response>(std::bind(&WithStreamedUnaryMethod_MethodB1::StreamedMethodB1, this, std::placeholders::_1, std::placeholders::_2))); + new ::grpc::StreamedUnaryHandler< ::grpc::testing::Request, ::grpc::testing::Response>(std::bind(&WithStreamedUnaryMethod_MethodB1::StreamedMethodB1, this, std::placeholders::_1, std::placeholders::_2))); } ~WithStreamedUnaryMethod_MethodB1() override { BaseClassMustBeDerivedFromService(this); diff --git a/test/cpp/microbenchmarks/bm_cq.cc b/test/cpp/microbenchmarks/bm_cq.cc index 6bb6ad8018a..18308a2e168 100644 --- a/test/cpp/microbenchmarks/bm_cq.cc +++ b/test/cpp/microbenchmarks/bm_cq.cc @@ -69,7 +69,7 @@ BENCHMARK(BM_CreateDestroyCore); static void DoneWithCompletionOnStack(grpc_exec_ctx* exec_ctx, void* arg, grpc_cq_completion* completion) {} -class DummyTag final : public internal::CompletionQueueTag { +class DummyTag final : public CompletionQueueTag { public: bool FinalizeResult(void** tag, bool* status) override { return true; } }; diff --git a/test/cpp/qps/server_sync.cc b/test/cpp/qps/server_sync.cc index 9954e2c0bfc..07e41817b38 100644 --- a/test/cpp/qps/server_sync.cc +++ b/test/cpp/qps/server_sync.cc @@ -112,8 +112,8 @@ class BenchmarkServiceImpl final : public BenchmarkService::Service { } private: - template - static Status ClientPull(ServerContext* context, R* stream, + static Status ClientPull(ServerContext* context, + ReaderInterface* stream, SimpleResponse* response) { SimpleRequest request; while (stream->Read(&request)) { @@ -126,8 +126,8 @@ class BenchmarkServiceImpl final : public BenchmarkService::Service { } return Status::OK; } - template - static Status ServerPush(ServerContext* context, W* stream, + static Status ServerPush(ServerContext* context, + WriterInterface* stream, const SimpleResponse& response, std::function done) { while ((done == nullptr) || !done()) { From bc81eee4d4384cb461b587400c3f534be2503e5c Mon Sep 17 00:00:00 2001 From: Vijay Pai Date: Tue, 25 Jul 2017 01:51:28 -0700 Subject: [PATCH 092/127] Remove a follow-on internal that was added post-internalization, keep the templated QPS worker rather than going back to internal API --- include/grpc++/impl/codegen/server_interface.h | 2 +- test/cpp/qps/server_sync.cc | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/grpc++/impl/codegen/server_interface.h b/include/grpc++/impl/codegen/server_interface.h index ef063a9718c..55937f19d7c 100644 --- a/include/grpc++/impl/codegen/server_interface.h +++ b/include/grpc++/impl/codegen/server_interface.h @@ -212,7 +212,7 @@ class ServerInterface : public CallHook { void* const registered_method_; ServerInterface* const server_; ServerContext* const context_; - internal::ServerAsyncStreamingInterface* const stream_; + ServerAsyncStreamingInterface* const stream_; CompletionQueue* const call_cq_; ServerCompletionQueue* const notification_cq_; void* const tag_; diff --git a/test/cpp/qps/server_sync.cc b/test/cpp/qps/server_sync.cc index 07e41817b38..9954e2c0bfc 100644 --- a/test/cpp/qps/server_sync.cc +++ b/test/cpp/qps/server_sync.cc @@ -112,8 +112,8 @@ class BenchmarkServiceImpl final : public BenchmarkService::Service { } private: - static Status ClientPull(ServerContext* context, - ReaderInterface* stream, + template + static Status ClientPull(ServerContext* context, R* stream, SimpleResponse* response) { SimpleRequest request; while (stream->Read(&request)) { @@ -126,8 +126,8 @@ class BenchmarkServiceImpl final : public BenchmarkService::Service { } return Status::OK; } - static Status ServerPush(ServerContext* context, - WriterInterface* stream, + template + static Status ServerPush(ServerContext* context, W* stream, const SimpleResponse& response, std::function done) { while ((done == nullptr) || !done()) { From 59ef64898a9aa3bbd9d0526c360315a77b662474 Mon Sep 17 00:00:00 2001 From: yang-g Date: Mon, 17 Jul 2017 13:52:24 -0700 Subject: [PATCH 093/127] Adding exec_ctx to avl vtable functions --- include/grpc/support/avl.h | 29 +- .../filters/client_channel/retry_throttle.c | 22 +- .../filters/client_channel/subchannel_index.c | 87 +- src/core/lib/support/avl.c | 177 +- test/core/support/avl_test.c | 3484 +++++++++-------- 5 files changed, 1906 insertions(+), 1893 deletions(-) diff --git a/include/grpc/support/avl.h b/include/grpc/support/avl.h index ed052e82229..cd029ef2a6c 100644 --- a/include/grpc/support/avl.h +++ b/include/grpc/support/avl.h @@ -31,18 +31,23 @@ typedef struct gpr_avl_node { long height; } gpr_avl_node; +/** vtable for the AVL tree + * The optional user_data is propagated from the top level gpr_avl_XXX API. + * From the same API call, multiple vtable functions may be called multiple + * times. + */ typedef struct gpr_avl_vtable { /** destroy a key */ - void (*destroy_key)(void *key); + void (*destroy_key)(void *key, void *user_data); /** copy a key, returning new value */ - void *(*copy_key)(void *key); + void *(*copy_key)(void *key, void *user_data); /** compare key1, key2; return <0 if key1 < key2, >0 if key1 > key2, 0 if key1 == key2 */ - long (*compare_keys)(void *key1, void *key2); + long (*compare_keys)(void *key1, void *key2, void *user_data); /** destroy a value */ - void (*destroy_value)(void *value); + void (*destroy_value)(void *value, void *user_data); /** copy a value */ - void *(*copy_value)(void *value); + void *(*copy_value)(void *value, void *user_data); } gpr_avl_vtable; /** "pointer" to an AVL tree - this is a reference @@ -57,25 +62,27 @@ typedef struct gpr_avl { GPRAPI gpr_avl gpr_avl_create(const gpr_avl_vtable *vtable); /** add a reference to an existing tree - returns the tree as a convenience */ -GPRAPI gpr_avl gpr_avl_ref(gpr_avl avl); +GPRAPI gpr_avl gpr_avl_ref(gpr_avl avl, void *user_data); /** remove a reference to a tree - destroying it if there are no references left */ -GPRAPI void gpr_avl_unref(gpr_avl avl); +GPRAPI void gpr_avl_unref(gpr_avl avl, void *user_data); /** return a new tree with (key, value) added to avl. implicitly unrefs avl to allow easy chaining. if key exists in avl, the new tree's key entry updated (i.e. a duplicate is not created) */ -GPRAPI gpr_avl gpr_avl_add(gpr_avl avl, void *key, void *value); +GPRAPI gpr_avl gpr_avl_add(gpr_avl avl, void *key, void *value, + void *user_data); /** return a new tree with key deleted implicitly unrefs avl to allow easy chaining. */ -GPRAPI gpr_avl gpr_avl_remove(gpr_avl avl, void *key); +GPRAPI gpr_avl gpr_avl_remove(gpr_avl avl, void *key, void *user_data); /** lookup key, and return the associated value. does not mutate avl. returns NULL if key is not found. */ -GPRAPI void *gpr_avl_get(gpr_avl avl, void *key); +GPRAPI void *gpr_avl_get(gpr_avl avl, void *key, void *user_data); /** Return 1 if avl contains key, 0 otherwise; if it has the key, sets *value to its value*/ -GPRAPI int gpr_avl_maybe_get(gpr_avl avl, void *key, void **value); +GPRAPI int gpr_avl_maybe_get(gpr_avl avl, void *key, void **value, + void *user_data); /** Return 1 if avl is empty, 0 otherwise */ GPRAPI int gpr_avl_is_empty(gpr_avl avl); diff --git a/src/core/ext/filters/client_channel/retry_throttle.c b/src/core/ext/filters/client_channel/retry_throttle.c index 3009e21d491..0c7a3ae6519 100644 --- a/src/core/ext/filters/client_channel/retry_throttle.c +++ b/src/core/ext/filters/client_channel/retry_throttle.c @@ -130,24 +130,28 @@ static grpc_server_retry_throttle_data* grpc_server_retry_throttle_data_create( // avl vtable for string -> server_retry_throttle_data map // -static void* copy_server_name(void* key) { return gpr_strdup(key); } +static void* copy_server_name(void* key, void* unused) { + return gpr_strdup(key); +} -static long compare_server_name(void* key1, void* key2) { +static long compare_server_name(void* key1, void* key2, void* unused) { return strcmp(key1, key2); } -static void destroy_server_retry_throttle_data(void* value) { +static void destroy_server_retry_throttle_data(void* value, void* unused) { grpc_server_retry_throttle_data* throttle_data = value; grpc_server_retry_throttle_data_unref(throttle_data); } -static void* copy_server_retry_throttle_data(void* value) { +static void* copy_server_retry_throttle_data(void* value, void* unused) { grpc_server_retry_throttle_data* throttle_data = value; return grpc_server_retry_throttle_data_ref(throttle_data); } +static void destroy_server_name(void* key, void* unused) { gpr_free(key); } + static const gpr_avl_vtable avl_vtable = { - gpr_free /* destroy_key */, copy_server_name, compare_server_name, + destroy_server_name, copy_server_name, compare_server_name, destroy_server_retry_throttle_data, copy_server_retry_throttle_data}; // @@ -164,19 +168,19 @@ void grpc_retry_throttle_map_init() { void grpc_retry_throttle_map_shutdown() { gpr_mu_destroy(&g_mu); - gpr_avl_unref(g_avl); + gpr_avl_unref(g_avl, NULL); } grpc_server_retry_throttle_data* grpc_retry_throttle_map_get_data_for_server( const char* server_name, int max_milli_tokens, int milli_token_ratio) { gpr_mu_lock(&g_mu); grpc_server_retry_throttle_data* throttle_data = - gpr_avl_get(g_avl, (char*)server_name); + gpr_avl_get(g_avl, (char*)server_name, NULL); if (throttle_data == NULL) { // Entry not found. Create a new one. throttle_data = grpc_server_retry_throttle_data_create( max_milli_tokens, milli_token_ratio, NULL); - g_avl = gpr_avl_add(g_avl, (char*)server_name, throttle_data); + g_avl = gpr_avl_add(g_avl, (char*)server_name, throttle_data, NULL); } else { if (throttle_data->max_milli_tokens != max_milli_tokens || throttle_data->milli_token_ratio != milli_token_ratio) { @@ -184,7 +188,7 @@ grpc_server_retry_throttle_data* grpc_retry_throttle_map_get_data_for_server( // the original one. throttle_data = grpc_server_retry_throttle_data_create( max_milli_tokens, milli_token_ratio, throttle_data); - g_avl = gpr_avl_add(g_avl, (char*)server_name, throttle_data); + g_avl = gpr_avl_add(g_avl, (char*)server_name, throttle_data, NULL); } else { // Entry found. Increase refcount. grpc_server_retry_throttle_data_ref(throttle_data); diff --git a/src/core/ext/filters/client_channel/subchannel_index.c b/src/core/ext/filters/client_channel/subchannel_index.c index a33ab950bff..15e42980af0 100644 --- a/src/core/ext/filters/client_channel/subchannel_index.c +++ b/src/core/ext/filters/client_channel/subchannel_index.c @@ -38,26 +38,8 @@ struct grpc_subchannel_key { grpc_subchannel_args args; }; -GPR_TLS_DECL(subchannel_index_exec_ctx); - static bool g_force_creation = false; -static void enter_ctx(grpc_exec_ctx *exec_ctx) { - GPR_ASSERT(gpr_tls_get(&subchannel_index_exec_ctx) == 0); - gpr_tls_set(&subchannel_index_exec_ctx, (intptr_t)exec_ctx); -} - -static void leave_ctx(grpc_exec_ctx *exec_ctx) { - GPR_ASSERT(gpr_tls_get(&subchannel_index_exec_ctx) == (intptr_t)exec_ctx); - gpr_tls_set(&subchannel_index_exec_ctx, 0); -} - -static grpc_exec_ctx *current_ctx() { - grpc_exec_ctx *c = (grpc_exec_ctx *)gpr_tls_get(&subchannel_index_exec_ctx); - GPR_ASSERT(c != NULL); - return c; -} - static grpc_subchannel_key *create_key( const grpc_subchannel_args *args, grpc_channel_args *(*copy_channel_args)(const grpc_channel_args *args)) { @@ -104,21 +86,25 @@ void grpc_subchannel_key_destroy(grpc_exec_ctx *exec_ctx, gpr_free(k); } -static void sck_avl_destroy(void *p) { - grpc_subchannel_key_destroy(current_ctx(), p); +static void sck_avl_destroy(void *p, void *user_data) { + grpc_exec_ctx *exec_ctx = (grpc_exec_ctx *)user_data; + grpc_subchannel_key_destroy(exec_ctx, p); } -static void *sck_avl_copy(void *p) { return subchannel_key_copy(p); } +static void *sck_avl_copy(void *p, void *unused) { + return subchannel_key_copy(p); +} -static long sck_avl_compare(void *a, void *b) { +static long sck_avl_compare(void *a, void *b, void *unused) { return grpc_subchannel_key_compare(a, b); } -static void scv_avl_destroy(void *p) { - GRPC_SUBCHANNEL_WEAK_UNREF(current_ctx(), p, "subchannel_index"); +static void scv_avl_destroy(void *p, void *user_data) { + grpc_exec_ctx *exec_ctx = (grpc_exec_ctx *)user_data; + GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, p, "subchannel_index"); } -static void *scv_avl_copy(void *p) { +static void *scv_avl_copy(void *p, void *unused) { GRPC_SUBCHANNEL_WEAK_REF(p, "subchannel_index"); return p; } @@ -133,38 +119,33 @@ static const gpr_avl_vtable subchannel_avl_vtable = { void grpc_subchannel_index_init(void) { g_subchannel_index = gpr_avl_create(&subchannel_avl_vtable); gpr_mu_init(&g_mu); - gpr_tls_init(&subchannel_index_exec_ctx); } void grpc_subchannel_index_shutdown(void) { + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; gpr_mu_destroy(&g_mu); - gpr_avl_unref(g_subchannel_index); - gpr_tls_destroy(&subchannel_index_exec_ctx); + gpr_avl_unref(g_subchannel_index, &exec_ctx); + grpc_exec_ctx_finish(&exec_ctx); } grpc_subchannel *grpc_subchannel_index_find(grpc_exec_ctx *exec_ctx, grpc_subchannel_key *key) { - enter_ctx(exec_ctx); - // Lock, and take a reference to the subchannel index. // We don't need to do the search under a lock as avl's are immutable. gpr_mu_lock(&g_mu); - gpr_avl index = gpr_avl_ref(g_subchannel_index); + gpr_avl index = gpr_avl_ref(g_subchannel_index, exec_ctx); gpr_mu_unlock(&g_mu); - grpc_subchannel *c = - GRPC_SUBCHANNEL_REF_FROM_WEAK_REF(gpr_avl_get(index, key), "index_find"); - gpr_avl_unref(index); + grpc_subchannel *c = GRPC_SUBCHANNEL_REF_FROM_WEAK_REF( + gpr_avl_get(index, key, exec_ctx), "index_find"); + gpr_avl_unref(index, exec_ctx); - leave_ctx(exec_ctx); return c; } grpc_subchannel *grpc_subchannel_index_register(grpc_exec_ctx *exec_ctx, grpc_subchannel_key *key, grpc_subchannel *constructed) { - enter_ctx(exec_ctx); - grpc_subchannel *c = NULL; bool need_to_unref_constructed; @@ -174,11 +155,11 @@ grpc_subchannel *grpc_subchannel_index_register(grpc_exec_ctx *exec_ctx, // Compare and swap loop: // - take a reference to the current index gpr_mu_lock(&g_mu); - gpr_avl index = gpr_avl_ref(g_subchannel_index); + gpr_avl index = gpr_avl_ref(g_subchannel_index, exec_ctx); gpr_mu_unlock(&g_mu); // - Check to see if a subchannel already exists - c = gpr_avl_get(index, key); + c = gpr_avl_get(index, key, exec_ctx); if (c != NULL) { c = GRPC_SUBCHANNEL_REF_FROM_WEAK_REF(c, "index_register"); } @@ -187,9 +168,9 @@ grpc_subchannel *grpc_subchannel_index_register(grpc_exec_ctx *exec_ctx, need_to_unref_constructed = true; } else { // no -> update the avl and compare/swap - gpr_avl updated = - gpr_avl_add(gpr_avl_ref(index), subchannel_key_copy(key), - GRPC_SUBCHANNEL_WEAK_REF(constructed, "index_register")); + gpr_avl updated = gpr_avl_add( + gpr_avl_ref(index, exec_ctx), subchannel_key_copy(key), + GRPC_SUBCHANNEL_WEAK_REF(constructed, "index_register"), exec_ctx); // it may happen (but it's expected to be unlikely) // that some other thread has changed the index: @@ -201,12 +182,11 @@ grpc_subchannel *grpc_subchannel_index_register(grpc_exec_ctx *exec_ctx, } gpr_mu_unlock(&g_mu); - gpr_avl_unref(updated); + gpr_avl_unref(updated, exec_ctx); } - gpr_avl_unref(index); + gpr_avl_unref(index, exec_ctx); } - leave_ctx(exec_ctx); if (need_to_unref_constructed) { GRPC_SUBCHANNEL_UNREF(exec_ctx, constructed, "index_register"); @@ -218,27 +198,26 @@ grpc_subchannel *grpc_subchannel_index_register(grpc_exec_ctx *exec_ctx, void grpc_subchannel_index_unregister(grpc_exec_ctx *exec_ctx, grpc_subchannel_key *key, grpc_subchannel *constructed) { - enter_ctx(exec_ctx); - bool done = false; while (!done) { // Compare and swap loop: // - take a reference to the current index gpr_mu_lock(&g_mu); - gpr_avl index = gpr_avl_ref(g_subchannel_index); + gpr_avl index = gpr_avl_ref(g_subchannel_index, exec_ctx); gpr_mu_unlock(&g_mu); // Check to see if this key still refers to the previously // registered subchannel - grpc_subchannel *c = gpr_avl_get(index, key); + grpc_subchannel *c = gpr_avl_get(index, key, exec_ctx); if (c != constructed) { - gpr_avl_unref(index); + gpr_avl_unref(index, exec_ctx); break; } // compare and swap the update (some other thread may have // mutated the index behind us) - gpr_avl updated = gpr_avl_remove(gpr_avl_ref(index), key); + gpr_avl updated = + gpr_avl_remove(gpr_avl_ref(index, exec_ctx), key, exec_ctx); gpr_mu_lock(&g_mu); if (index.root == g_subchannel_index.root) { @@ -247,11 +226,9 @@ void grpc_subchannel_index_unregister(grpc_exec_ctx *exec_ctx, } gpr_mu_unlock(&g_mu); - gpr_avl_unref(updated); - gpr_avl_unref(index); + gpr_avl_unref(updated, exec_ctx); + gpr_avl_unref(index, exec_ctx); } - - leave_ctx(exec_ctx); } void grpc_subchannel_index_test_only_set_force_creation(bool force_creation) { diff --git a/src/core/lib/support/avl.c b/src/core/lib/support/avl.c index a6178fdbced..a58551e259e 100644 --- a/src/core/lib/support/avl.c +++ b/src/core/lib/support/avl.c @@ -32,22 +32,23 @@ gpr_avl gpr_avl_create(const gpr_avl_vtable *vtable) { return out; } -static gpr_avl_node *ref_node(gpr_avl_node *node) { +static gpr_avl_node *ref_node(gpr_avl_node *node, void *user_data) { if (node) { gpr_ref(&node->refs); } return node; } -static void unref_node(const gpr_avl_vtable *vtable, gpr_avl_node *node) { +static void unref_node(const gpr_avl_vtable *vtable, gpr_avl_node *node, + void *user_data) { if (node == NULL) { return; } if (gpr_unref(&node->refs)) { - vtable->destroy_key(node->key); - vtable->destroy_value(node->value); - unref_node(vtable, node->left); - unref_node(vtable, node->right); + vtable->destroy_key(node->key, user_data); + vtable->destroy_value(node->value, user_data); + unref_node(vtable, node->left, user_data); + unref_node(vtable, node->right, user_data); gpr_free(node); } } @@ -87,30 +88,30 @@ gpr_avl_node *new_node(void *key, void *value, gpr_avl_node *left, } static gpr_avl_node *get(const gpr_avl_vtable *vtable, gpr_avl_node *node, - void *key) { + void *key, void *user_data) { long cmp; if (node == NULL) { return NULL; } - cmp = vtable->compare_keys(node->key, key); + cmp = vtable->compare_keys(node->key, key, user_data); if (cmp == 0) { return node; } else if (cmp > 0) { - return get(vtable, node->left, key); + return get(vtable, node->left, key, user_data); } else { - return get(vtable, node->right, key); + return get(vtable, node->right, key, user_data); } } -void *gpr_avl_get(gpr_avl avl, void *key) { - gpr_avl_node *node = get(avl.vtable, avl.root, key); +void *gpr_avl_get(gpr_avl avl, void *key, void *user_data) { + gpr_avl_node *node = get(avl.vtable, avl.root, key, user_data); return node ? node->value : NULL; } -int gpr_avl_maybe_get(gpr_avl avl, void *key, void **value) { - gpr_avl_node *node = get(avl.vtable, avl.root, key); +int gpr_avl_maybe_get(gpr_avl avl, void *key, void **value, void *user_data) { + gpr_avl_node *node = get(avl.vtable, avl.root, key, user_data); if (node != NULL) { *value = node->value; return 1; @@ -120,70 +121,79 @@ int gpr_avl_maybe_get(gpr_avl avl, void *key, void **value) { static gpr_avl_node *rotate_left(const gpr_avl_vtable *vtable, void *key, void *value, gpr_avl_node *left, - gpr_avl_node *right) { + gpr_avl_node *right, void *user_data) { gpr_avl_node *n = - new_node(vtable->copy_key(right->key), vtable->copy_value(right->value), - new_node(key, value, left, ref_node(right->left)), - ref_node(right->right)); - unref_node(vtable, right); + new_node(vtable->copy_key(right->key, user_data), + vtable->copy_value(right->value, user_data), + new_node(key, value, left, ref_node(right->left, user_data)), + ref_node(right->right, user_data)); + unref_node(vtable, right, user_data); return n; } static gpr_avl_node *rotate_right(const gpr_avl_vtable *vtable, void *key, void *value, gpr_avl_node *left, - gpr_avl_node *right) { - gpr_avl_node *n = new_node( - vtable->copy_key(left->key), vtable->copy_value(left->value), - ref_node(left->left), new_node(key, value, ref_node(left->right), right)); - unref_node(vtable, left); + gpr_avl_node *right, void *user_data) { + gpr_avl_node *n = + new_node(vtable->copy_key(left->key, user_data), + vtable->copy_value(left->value, user_data), + ref_node(left->left, user_data), + new_node(key, value, ref_node(left->right, user_data), right)); + unref_node(vtable, left, user_data); return n; } static gpr_avl_node *rotate_left_right(const gpr_avl_vtable *vtable, void *key, void *value, gpr_avl_node *left, - gpr_avl_node *right) { + gpr_avl_node *right, void *user_data) { /* rotate_right(..., rotate_left(left), right) */ gpr_avl_node *n = new_node( - vtable->copy_key(left->right->key), - vtable->copy_value(left->right->value), - new_node(vtable->copy_key(left->key), vtable->copy_value(left->value), - ref_node(left->left), ref_node(left->right->left)), - new_node(key, value, ref_node(left->right->right), right)); - unref_node(vtable, left); + vtable->copy_key(left->right->key, user_data), + vtable->copy_value(left->right->value, user_data), + new_node(vtable->copy_key(left->key, user_data), + vtable->copy_value(left->value, user_data), + ref_node(left->left, user_data), + ref_node(left->right->left, user_data)), + new_node(key, value, ref_node(left->right->right, user_data), right)); + unref_node(vtable, left, user_data); return n; } static gpr_avl_node *rotate_right_left(const gpr_avl_vtable *vtable, void *key, void *value, gpr_avl_node *left, - gpr_avl_node *right) { + gpr_avl_node *right, void *user_data) { /* rotate_left(..., left, rotate_right(right)) */ gpr_avl_node *n = new_node( - vtable->copy_key(right->left->key), - vtable->copy_value(right->left->value), - new_node(key, value, left, ref_node(right->left->left)), - new_node(vtable->copy_key(right->key), vtable->copy_value(right->value), - ref_node(right->left->right), ref_node(right->right))); - unref_node(vtable, right); + vtable->copy_key(right->left->key, user_data), + vtable->copy_value(right->left->value, user_data), + new_node(key, value, left, ref_node(right->left->left, user_data)), + new_node(vtable->copy_key(right->key, user_data), + vtable->copy_value(right->value, user_data), + ref_node(right->left->right, user_data), + ref_node(right->right, user_data))); + unref_node(vtable, right, user_data); return n; } static gpr_avl_node *rebalance(const gpr_avl_vtable *vtable, void *key, void *value, gpr_avl_node *left, - gpr_avl_node *right) { + gpr_avl_node *right, void *user_data) { switch (node_height(left) - node_height(right)) { case 2: if (node_height(left->left) - node_height(left->right) == -1) { return assert_invariants( - rotate_left_right(vtable, key, value, left, right)); + rotate_left_right(vtable, key, value, left, right, user_data)); } else { - return assert_invariants(rotate_right(vtable, key, value, left, right)); + return assert_invariants( + rotate_right(vtable, key, value, left, right, user_data)); } case -2: if (node_height(right->left) - node_height(right->right) == 1) { return assert_invariants( - rotate_right_left(vtable, key, value, left, right)); + rotate_right_left(vtable, key, value, left, right, user_data)); } else { - return assert_invariants(rotate_left(vtable, key, value, left, right)); + return assert_invariants( + rotate_left(vtable, key, value, left, right, user_data)); } default: return assert_invariants(new_node(key, value, left, right)); @@ -191,30 +201,34 @@ static gpr_avl_node *rebalance(const gpr_avl_vtable *vtable, void *key, } static gpr_avl_node *add_key(const gpr_avl_vtable *vtable, gpr_avl_node *node, - void *key, void *value) { + void *key, void *value, void *user_data) { long cmp; if (node == NULL) { return new_node(key, value, NULL, NULL); } - cmp = vtable->compare_keys(node->key, key); + cmp = vtable->compare_keys(node->key, key, user_data); if (cmp == 0) { - return new_node(key, value, ref_node(node->left), ref_node(node->right)); + return new_node(key, value, ref_node(node->left, user_data), + ref_node(node->right, user_data)); } else if (cmp > 0) { - return rebalance( - vtable, vtable->copy_key(node->key), vtable->copy_value(node->value), - add_key(vtable, node->left, key, value), ref_node(node->right)); + return rebalance(vtable, vtable->copy_key(node->key, user_data), + vtable->copy_value(node->value, user_data), + add_key(vtable, node->left, key, value, user_data), + ref_node(node->right, user_data), user_data); } else { - return rebalance(vtable, vtable->copy_key(node->key), - vtable->copy_value(node->value), ref_node(node->left), - add_key(vtable, node->right, key, value)); + return rebalance(vtable, vtable->copy_key(node->key, user_data), + vtable->copy_value(node->value, user_data), + ref_node(node->left, user_data), + add_key(vtable, node->right, key, value, user_data), + user_data); } } -gpr_avl gpr_avl_add(gpr_avl avl, void *key, void *value) { +gpr_avl gpr_avl_add(gpr_avl avl, void *key, void *value, void *user_data) { gpr_avl_node *old_root = avl.root; - avl.root = add_key(avl.vtable, avl.root, key, value); + avl.root = add_key(avl.vtable, avl.root, key, value, user_data); assert_invariants(avl.root); - unref_node(avl.vtable, old_root); + unref_node(avl.vtable, old_root, user_data); return avl; } @@ -233,52 +247,61 @@ static gpr_avl_node *in_order_tail(gpr_avl_node *node) { } static gpr_avl_node *remove_key(const gpr_avl_vtable *vtable, - gpr_avl_node *node, void *key) { + gpr_avl_node *node, void *key, + void *user_data) { long cmp; if (node == NULL) { return NULL; } - cmp = vtable->compare_keys(node->key, key); + cmp = vtable->compare_keys(node->key, key, user_data); if (cmp == 0) { if (node->left == NULL) { - return ref_node(node->right); + return ref_node(node->right, user_data); } else if (node->right == NULL) { - return ref_node(node->left); + return ref_node(node->left, user_data); } else if (node->left->height < node->right->height) { gpr_avl_node *h = in_order_head(node->right); - return rebalance(vtable, vtable->copy_key(h->key), - vtable->copy_value(h->value), ref_node(node->left), - remove_key(vtable, node->right, h->key)); + return rebalance(vtable, vtable->copy_key(h->key, user_data), + vtable->copy_value(h->value, user_data), + ref_node(node->left, user_data), + remove_key(vtable, node->right, h->key, user_data), + user_data); } else { gpr_avl_node *h = in_order_tail(node->left); - return rebalance( - vtable, vtable->copy_key(h->key), vtable->copy_value(h->value), - remove_key(vtable, node->left, h->key), ref_node(node->right)); + return rebalance(vtable, vtable->copy_key(h->key, user_data), + vtable->copy_value(h->value, user_data), + remove_key(vtable, node->left, h->key, user_data), + ref_node(node->right, user_data), user_data); } } else if (cmp > 0) { - return rebalance( - vtable, vtable->copy_key(node->key), vtable->copy_value(node->value), - remove_key(vtable, node->left, key), ref_node(node->right)); + return rebalance(vtable, vtable->copy_key(node->key, user_data), + vtable->copy_value(node->value, user_data), + remove_key(vtable, node->left, key, user_data), + ref_node(node->right, user_data), user_data); } else { - return rebalance(vtable, vtable->copy_key(node->key), - vtable->copy_value(node->value), ref_node(node->left), - remove_key(vtable, node->right, key)); + return rebalance(vtable, vtable->copy_key(node->key, user_data), + vtable->copy_value(node->value, user_data), + ref_node(node->left, user_data), + remove_key(vtable, node->right, key, user_data), + user_data); } } -gpr_avl gpr_avl_remove(gpr_avl avl, void *key) { +gpr_avl gpr_avl_remove(gpr_avl avl, void *key, void *user_data) { gpr_avl_node *old_root = avl.root; - avl.root = remove_key(avl.vtable, avl.root, key); + avl.root = remove_key(avl.vtable, avl.root, key, user_data); assert_invariants(avl.root); - unref_node(avl.vtable, old_root); + unref_node(avl.vtable, old_root, user_data); return avl; } -gpr_avl gpr_avl_ref(gpr_avl avl) { - ref_node(avl.root); +gpr_avl gpr_avl_ref(gpr_avl avl, void *user_data) { + ref_node(avl.root, user_data); return avl; } -void gpr_avl_unref(gpr_avl avl) { unref_node(avl.vtable, avl.root); } +void gpr_avl_unref(gpr_avl avl, void *user_data) { + unref_node(avl.vtable, avl.root, user_data); +} int gpr_avl_is_empty(gpr_avl avl) { return avl.root == NULL; } diff --git a/test/core/support/avl_test.c b/test/core/support/avl_test.c index cd352d3d1d6..37424d64057 100644 --- a/test/core/support/avl_test.c +++ b/test/core/support/avl_test.c @@ -33,29 +33,31 @@ static int *box(int x) { return b; } -static long int_compare(void *int1, void *int2) { +static long int_compare(void *int1, void *int2, void *unused) { return (*(int *)int1) - (*(int *)int2); } -static void *int_copy(void *p) { return box(*(int *)p); } +static void *int_copy(void *p, void *unused) { return box(*(int *)p); } -static const gpr_avl_vtable int_int_vtable = {gpr_free, int_copy, int_compare, - gpr_free, int_copy}; +static void destroy(void *p, void *unused) { gpr_free(p); } + +static const gpr_avl_vtable int_int_vtable = {destroy, int_copy, int_compare, + destroy, int_copy}; static void check_get(gpr_avl avl, int key, int value) { int *k = box(key); - GPR_ASSERT(*(int *)gpr_avl_get(avl, k) == value); + GPR_ASSERT(*(int *)gpr_avl_get(avl, k, NULL) == value); gpr_free(k); } static void check_negget(gpr_avl avl, int key) { int *k = box(key); - GPR_ASSERT(gpr_avl_get(avl, k) == NULL); + GPR_ASSERT(gpr_avl_get(avl, k, NULL) == NULL); gpr_free(k); } static gpr_avl remove_int(gpr_avl avl, int key) { int *k = box(key); - avl = gpr_avl_remove(avl, k); + avl = gpr_avl_remove(avl, k, NULL); gpr_free(k); return avl; } @@ -64,94 +66,94 @@ static void test_get(void) { gpr_avl avl; gpr_log(GPR_DEBUG, "test_get"); avl = gpr_avl_create(&int_int_vtable); - avl = gpr_avl_add(avl, box(1), box(11)); - avl = gpr_avl_add(avl, box(2), box(22)); - avl = gpr_avl_add(avl, box(3), box(33)); + avl = gpr_avl_add(avl, box(1), box(11), NULL); + avl = gpr_avl_add(avl, box(2), box(22), NULL); + avl = gpr_avl_add(avl, box(3), box(33), NULL); check_get(avl, 1, 11); check_get(avl, 2, 22); check_get(avl, 3, 33); check_negget(avl, 4); - gpr_avl_unref(avl); + gpr_avl_unref(avl, NULL); } static void test_ll(void) { gpr_avl avl; gpr_log(GPR_DEBUG, "test_ll"); avl = gpr_avl_create(&int_int_vtable); - avl = gpr_avl_add(avl, box(5), box(1)); - avl = gpr_avl_add(avl, box(4), box(2)); - avl = gpr_avl_add(avl, box(3), box(3)); + avl = gpr_avl_add(avl, box(5), box(1), NULL); + avl = gpr_avl_add(avl, box(4), box(2), NULL); + avl = gpr_avl_add(avl, box(3), box(3), NULL); GPR_ASSERT(*(int *)avl.root->key == 4); GPR_ASSERT(*(int *)avl.root->left->key == 3); GPR_ASSERT(*(int *)avl.root->right->key == 5); - gpr_avl_unref(avl); + gpr_avl_unref(avl, NULL); } static void test_lr(void) { gpr_avl avl; gpr_log(GPR_DEBUG, "test_lr"); avl = gpr_avl_create(&int_int_vtable); - avl = gpr_avl_add(avl, box(5), box(1)); - avl = gpr_avl_add(avl, box(3), box(2)); - avl = gpr_avl_add(avl, box(4), box(3)); + avl = gpr_avl_add(avl, box(5), box(1), NULL); + avl = gpr_avl_add(avl, box(3), box(2), NULL); + avl = gpr_avl_add(avl, box(4), box(3), NULL); GPR_ASSERT(*(int *)avl.root->key == 4); GPR_ASSERT(*(int *)avl.root->left->key == 3); GPR_ASSERT(*(int *)avl.root->right->key == 5); - gpr_avl_unref(avl); + gpr_avl_unref(avl, NULL); } static void test_rr(void) { gpr_avl avl; gpr_log(GPR_DEBUG, "test_rr"); avl = gpr_avl_create(&int_int_vtable); - avl = gpr_avl_add(avl, box(3), box(1)); - avl = gpr_avl_add(avl, box(4), box(2)); - avl = gpr_avl_add(avl, box(5), box(3)); + avl = gpr_avl_add(avl, box(3), box(1), NULL); + avl = gpr_avl_add(avl, box(4), box(2), NULL); + avl = gpr_avl_add(avl, box(5), box(3), NULL); GPR_ASSERT(*(int *)avl.root->key == 4); GPR_ASSERT(*(int *)avl.root->left->key == 3); GPR_ASSERT(*(int *)avl.root->right->key == 5); - gpr_avl_unref(avl); + gpr_avl_unref(avl, NULL); } static void test_rl(void) { gpr_avl avl; gpr_log(GPR_DEBUG, "test_rl"); avl = gpr_avl_create(&int_int_vtable); - avl = gpr_avl_add(avl, box(3), box(1)); - avl = gpr_avl_add(avl, box(5), box(2)); - avl = gpr_avl_add(avl, box(4), box(3)); + avl = gpr_avl_add(avl, box(3), box(1), NULL); + avl = gpr_avl_add(avl, box(5), box(2), NULL); + avl = gpr_avl_add(avl, box(4), box(3), NULL); GPR_ASSERT(*(int *)avl.root->key == 4); GPR_ASSERT(*(int *)avl.root->left->key == 3); GPR_ASSERT(*(int *)avl.root->right->key == 5); - gpr_avl_unref(avl); + gpr_avl_unref(avl, NULL); } static void test_unbalanced(void) { gpr_avl avl; gpr_log(GPR_DEBUG, "test_unbalanced"); avl = gpr_avl_create(&int_int_vtable); - avl = gpr_avl_add(avl, box(5), box(1)); - avl = gpr_avl_add(avl, box(4), box(2)); - avl = gpr_avl_add(avl, box(3), box(3)); - avl = gpr_avl_add(avl, box(2), box(4)); - avl = gpr_avl_add(avl, box(1), box(5)); + avl = gpr_avl_add(avl, box(5), box(1), NULL); + avl = gpr_avl_add(avl, box(4), box(2), NULL); + avl = gpr_avl_add(avl, box(3), box(3), NULL); + avl = gpr_avl_add(avl, box(2), box(4), NULL); + avl = gpr_avl_add(avl, box(1), box(5), NULL); GPR_ASSERT(*(int *)avl.root->key == 4); GPR_ASSERT(*(int *)avl.root->left->key == 2); GPR_ASSERT(*(int *)avl.root->left->left->key == 1); GPR_ASSERT(*(int *)avl.root->left->right->key == 3); GPR_ASSERT(*(int *)avl.root->right->key == 5); - gpr_avl_unref(avl); + gpr_avl_unref(avl, NULL); } static void test_replace(void) { gpr_avl avl; gpr_log(GPR_DEBUG, "test_replace"); avl = gpr_avl_create(&int_int_vtable); - avl = gpr_avl_add(avl, box(1), box(1)); - avl = gpr_avl_add(avl, box(1), box(2)); + avl = gpr_avl_add(avl, box(1), box(1), NULL); + avl = gpr_avl_add(avl, box(1), box(2), NULL); check_get(avl, 1, 2); check_negget(avl, 2); - gpr_avl_unref(avl); + gpr_avl_unref(avl, NULL); } static void test_remove(void) { @@ -159,36 +161,36 @@ static void test_remove(void) { gpr_avl avl3, avl4, avl5, avln; gpr_log(GPR_DEBUG, "test_remove"); avl = gpr_avl_create(&int_int_vtable); - avl = gpr_avl_add(avl, box(3), box(1)); - avl = gpr_avl_add(avl, box(4), box(2)); - avl = gpr_avl_add(avl, box(5), box(3)); + avl = gpr_avl_add(avl, box(3), box(1), NULL); + avl = gpr_avl_add(avl, box(4), box(2), NULL); + avl = gpr_avl_add(avl, box(5), box(3), NULL); - avl3 = remove_int(gpr_avl_ref(avl), 3); - avl4 = remove_int(gpr_avl_ref(avl), 4); - avl5 = remove_int(gpr_avl_ref(avl), 5); - avln = remove_int(gpr_avl_ref(avl), 1); + avl3 = remove_int(gpr_avl_ref(avl, NULL), 3); + avl4 = remove_int(gpr_avl_ref(avl, NULL), 4); + avl5 = remove_int(gpr_avl_ref(avl, NULL), 5); + avln = remove_int(gpr_avl_ref(avl, NULL), 1); - gpr_avl_unref(avl); + gpr_avl_unref(avl, NULL); check_negget(avl3, 3); check_get(avl3, 4, 2); check_get(avl3, 5, 3); - gpr_avl_unref(avl3); + gpr_avl_unref(avl3, NULL); check_get(avl4, 3, 1); check_negget(avl4, 4); check_get(avl4, 5, 3); - gpr_avl_unref(avl4); + gpr_avl_unref(avl4, NULL); check_get(avl5, 3, 1); check_get(avl5, 4, 2); check_negget(avl5, 5); - gpr_avl_unref(avl5); + gpr_avl_unref(avl5, NULL); check_get(avln, 3, 1); check_get(avln, 4, 2); check_get(avln, 5, 3); - gpr_avl_unref(avln); + gpr_avl_unref(avln, NULL); } static void test_badcase1(void) { @@ -197,44 +199,44 @@ static void test_badcase1(void) { gpr_log(GPR_DEBUG, "test_badcase1"); avl = gpr_avl_create(&int_int_vtable); - avl = gpr_avl_add(avl, box(88), box(1)); + avl = gpr_avl_add(avl, box(88), box(1), NULL); avl = remove_int(avl, 643); avl = remove_int(avl, 983); - avl = gpr_avl_add(avl, box(985), box(4)); - avl = gpr_avl_add(avl, box(640), box(5)); - avl = gpr_avl_add(avl, box(41), box(6)); - avl = gpr_avl_add(avl, box(112), box(7)); - avl = gpr_avl_add(avl, box(342), box(8)); + avl = gpr_avl_add(avl, box(985), box(4), NULL); + avl = gpr_avl_add(avl, box(640), box(5), NULL); + avl = gpr_avl_add(avl, box(41), box(6), NULL); + avl = gpr_avl_add(avl, box(112), box(7), NULL); + avl = gpr_avl_add(avl, box(342), box(8), NULL); avl = remove_int(avl, 1013); - avl = gpr_avl_add(avl, box(434), box(10)); - avl = gpr_avl_add(avl, box(520), box(11)); - avl = gpr_avl_add(avl, box(231), box(12)); - avl = gpr_avl_add(avl, box(852), box(13)); + avl = gpr_avl_add(avl, box(434), box(10), NULL); + avl = gpr_avl_add(avl, box(520), box(11), NULL); + avl = gpr_avl_add(avl, box(231), box(12), NULL); + avl = gpr_avl_add(avl, box(852), box(13), NULL); avl = remove_int(avl, 461); - avl = gpr_avl_add(avl, box(108), box(15)); - avl = gpr_avl_add(avl, box(806), box(16)); - avl = gpr_avl_add(avl, box(827), box(17)); + avl = gpr_avl_add(avl, box(108), box(15), NULL); + avl = gpr_avl_add(avl, box(806), box(16), NULL); + avl = gpr_avl_add(avl, box(827), box(17), NULL); avl = remove_int(avl, 796); - avl = gpr_avl_add(avl, box(340), box(19)); - avl = gpr_avl_add(avl, box(498), box(20)); - avl = gpr_avl_add(avl, box(203), box(21)); - avl = gpr_avl_add(avl, box(751), box(22)); - avl = gpr_avl_add(avl, box(150), box(23)); + avl = gpr_avl_add(avl, box(340), box(19), NULL); + avl = gpr_avl_add(avl, box(498), box(20), NULL); + avl = gpr_avl_add(avl, box(203), box(21), NULL); + avl = gpr_avl_add(avl, box(751), box(22), NULL); + avl = gpr_avl_add(avl, box(150), box(23), NULL); avl = remove_int(avl, 237); - avl = gpr_avl_add(avl, box(830), box(25)); + avl = gpr_avl_add(avl, box(830), box(25), NULL); avl = remove_int(avl, 1007); avl = remove_int(avl, 394); - avl = gpr_avl_add(avl, box(65), box(28)); + avl = gpr_avl_add(avl, box(65), box(28), NULL); avl = remove_int(avl, 904); avl = remove_int(avl, 123); - avl = gpr_avl_add(avl, box(238), box(31)); - avl = gpr_avl_add(avl, box(184), box(32)); + avl = gpr_avl_add(avl, box(238), box(31), NULL); + avl = gpr_avl_add(avl, box(184), box(32), NULL); avl = remove_int(avl, 331); - avl = gpr_avl_add(avl, box(827), box(34)); + avl = gpr_avl_add(avl, box(827), box(34), NULL); check_get(avl, 830, 25); - gpr_avl_unref(avl); + gpr_avl_unref(avl, NULL); } static void test_badcase2(void) { @@ -243,254 +245,254 @@ static void test_badcase2(void) { gpr_log(GPR_DEBUG, "test_badcase2"); avl = gpr_avl_create(&int_int_vtable); - avl = gpr_avl_add(avl, box(288), box(1)); + avl = gpr_avl_add(avl, box(288), box(1), NULL); avl = remove_int(avl, 415); - avl = gpr_avl_add(avl, box(953), box(3)); - avl = gpr_avl_add(avl, box(101), box(4)); - avl = gpr_avl_add(avl, box(516), box(5)); - avl = gpr_avl_add(avl, box(547), box(6)); - avl = gpr_avl_add(avl, box(467), box(7)); - avl = gpr_avl_add(avl, box(793), box(8)); + avl = gpr_avl_add(avl, box(953), box(3), NULL); + avl = gpr_avl_add(avl, box(101), box(4), NULL); + avl = gpr_avl_add(avl, box(516), box(5), NULL); + avl = gpr_avl_add(avl, box(547), box(6), NULL); + avl = gpr_avl_add(avl, box(467), box(7), NULL); + avl = gpr_avl_add(avl, box(793), box(8), NULL); avl = remove_int(avl, 190); - avl = gpr_avl_add(avl, box(687), box(10)); - avl = gpr_avl_add(avl, box(242), box(11)); - avl = gpr_avl_add(avl, box(142), box(12)); + avl = gpr_avl_add(avl, box(687), box(10), NULL); + avl = gpr_avl_add(avl, box(242), box(11), NULL); + avl = gpr_avl_add(avl, box(142), box(12), NULL); avl = remove_int(avl, 705); avl = remove_int(avl, 578); avl = remove_int(avl, 767); avl = remove_int(avl, 183); - avl = gpr_avl_add(avl, box(950), box(17)); - avl = gpr_avl_add(avl, box(622), box(18)); + avl = gpr_avl_add(avl, box(950), box(17), NULL); + avl = gpr_avl_add(avl, box(622), box(18), NULL); avl = remove_int(avl, 513); avl = remove_int(avl, 429); - avl = gpr_avl_add(avl, box(205), box(21)); + avl = gpr_avl_add(avl, box(205), box(21), NULL); avl = remove_int(avl, 663); avl = remove_int(avl, 953); avl = remove_int(avl, 892); - avl = gpr_avl_add(avl, box(236), box(25)); + avl = gpr_avl_add(avl, box(236), box(25), NULL); avl = remove_int(avl, 982); avl = remove_int(avl, 201); avl = remove_int(avl, 684); - avl = gpr_avl_add(avl, box(572), box(29)); + avl = gpr_avl_add(avl, box(572), box(29), NULL); avl = remove_int(avl, 817); - avl = gpr_avl_add(avl, box(970), box(31)); + avl = gpr_avl_add(avl, box(970), box(31), NULL); avl = remove_int(avl, 347); avl = remove_int(avl, 574); - avl = gpr_avl_add(avl, box(752), box(34)); - avl = gpr_avl_add(avl, box(670), box(35)); - avl = gpr_avl_add(avl, box(69), box(36)); + avl = gpr_avl_add(avl, box(752), box(34), NULL); + avl = gpr_avl_add(avl, box(670), box(35), NULL); + avl = gpr_avl_add(avl, box(69), box(36), NULL); avl = remove_int(avl, 111); avl = remove_int(avl, 523); - avl = gpr_avl_add(avl, box(141), box(39)); + avl = gpr_avl_add(avl, box(141), box(39), NULL); avl = remove_int(avl, 159); - avl = gpr_avl_add(avl, box(947), box(41)); - avl = gpr_avl_add(avl, box(855), box(42)); + avl = gpr_avl_add(avl, box(947), box(41), NULL); + avl = gpr_avl_add(avl, box(855), box(42), NULL); avl = remove_int(avl, 218); avl = remove_int(avl, 6); - avl = gpr_avl_add(avl, box(753), box(45)); + avl = gpr_avl_add(avl, box(753), box(45), NULL); avl = remove_int(avl, 82); avl = remove_int(avl, 799); - avl = gpr_avl_add(avl, box(572), box(48)); + avl = gpr_avl_add(avl, box(572), box(48), NULL); avl = remove_int(avl, 376); avl = remove_int(avl, 413); - avl = gpr_avl_add(avl, box(458), box(51)); + avl = gpr_avl_add(avl, box(458), box(51), NULL); avl = remove_int(avl, 897); - avl = gpr_avl_add(avl, box(191), box(53)); - avl = gpr_avl_add(avl, box(609), box(54)); + avl = gpr_avl_add(avl, box(191), box(53), NULL); + avl = gpr_avl_add(avl, box(609), box(54), NULL); avl = remove_int(avl, 787); avl = remove_int(avl, 710); avl = remove_int(avl, 886); avl = remove_int(avl, 835); avl = remove_int(avl, 33); - avl = gpr_avl_add(avl, box(871), box(60)); + avl = gpr_avl_add(avl, box(871), box(60), NULL); avl = remove_int(avl, 641); - avl = gpr_avl_add(avl, box(462), box(62)); + avl = gpr_avl_add(avl, box(462), box(62), NULL); avl = remove_int(avl, 359); avl = remove_int(avl, 767); - avl = gpr_avl_add(avl, box(310), box(65)); + avl = gpr_avl_add(avl, box(310), box(65), NULL); avl = remove_int(avl, 757); avl = remove_int(avl, 639); avl = remove_int(avl, 314); - avl = gpr_avl_add(avl, box(2), box(69)); + avl = gpr_avl_add(avl, box(2), box(69), NULL); avl = remove_int(avl, 138); - avl = gpr_avl_add(avl, box(669), box(71)); + avl = gpr_avl_add(avl, box(669), box(71), NULL); avl = remove_int(avl, 477); - avl = gpr_avl_add(avl, box(366), box(73)); - avl = gpr_avl_add(avl, box(612), box(74)); - avl = gpr_avl_add(avl, box(106), box(75)); + avl = gpr_avl_add(avl, box(366), box(73), NULL); + avl = gpr_avl_add(avl, box(612), box(74), NULL); + avl = gpr_avl_add(avl, box(106), box(75), NULL); avl = remove_int(avl, 161); - avl = gpr_avl_add(avl, box(388), box(77)); - avl = gpr_avl_add(avl, box(141), box(78)); + avl = gpr_avl_add(avl, box(388), box(77), NULL); + avl = gpr_avl_add(avl, box(141), box(78), NULL); avl = remove_int(avl, 633); avl = remove_int(avl, 459); - avl = gpr_avl_add(avl, box(40), box(81)); + avl = gpr_avl_add(avl, box(40), box(81), NULL); avl = remove_int(avl, 689); - avl = gpr_avl_add(avl, box(823), box(83)); + avl = gpr_avl_add(avl, box(823), box(83), NULL); avl = remove_int(avl, 485); - avl = gpr_avl_add(avl, box(903), box(85)); - avl = gpr_avl_add(avl, box(592), box(86)); + avl = gpr_avl_add(avl, box(903), box(85), NULL); + avl = gpr_avl_add(avl, box(592), box(86), NULL); avl = remove_int(avl, 448); - avl = gpr_avl_add(avl, box(56), box(88)); + avl = gpr_avl_add(avl, box(56), box(88), NULL); avl = remove_int(avl, 333); - avl = gpr_avl_add(avl, box(189), box(90)); - avl = gpr_avl_add(avl, box(103), box(91)); + avl = gpr_avl_add(avl, box(189), box(90), NULL); + avl = gpr_avl_add(avl, box(103), box(91), NULL); avl = remove_int(avl, 164); avl = remove_int(avl, 974); - avl = gpr_avl_add(avl, box(215), box(94)); + avl = gpr_avl_add(avl, box(215), box(94), NULL); avl = remove_int(avl, 189); avl = remove_int(avl, 504); - avl = gpr_avl_add(avl, box(868), box(97)); + avl = gpr_avl_add(avl, box(868), box(97), NULL); avl = remove_int(avl, 909); avl = remove_int(avl, 148); avl = remove_int(avl, 469); - avl = gpr_avl_add(avl, box(994), box(101)); - avl = gpr_avl_add(avl, box(576), box(102)); + avl = gpr_avl_add(avl, box(994), box(101), NULL); + avl = gpr_avl_add(avl, box(576), box(102), NULL); avl = remove_int(avl, 82); avl = remove_int(avl, 209); - avl = gpr_avl_add(avl, box(276), box(105)); + avl = gpr_avl_add(avl, box(276), box(105), NULL); avl = remove_int(avl, 856); - avl = gpr_avl_add(avl, box(750), box(107)); + avl = gpr_avl_add(avl, box(750), box(107), NULL); avl = remove_int(avl, 871); - avl = gpr_avl_add(avl, box(301), box(109)); + avl = gpr_avl_add(avl, box(301), box(109), NULL); avl = remove_int(avl, 260); avl = remove_int(avl, 737); avl = remove_int(avl, 719); - avl = gpr_avl_add(avl, box(933), box(113)); - avl = gpr_avl_add(avl, box(225), box(114)); - avl = gpr_avl_add(avl, box(975), box(115)); - avl = gpr_avl_add(avl, box(86), box(116)); + avl = gpr_avl_add(avl, box(933), box(113), NULL); + avl = gpr_avl_add(avl, box(225), box(114), NULL); + avl = gpr_avl_add(avl, box(975), box(115), NULL); + avl = gpr_avl_add(avl, box(86), box(116), NULL); avl = remove_int(avl, 732); - avl = gpr_avl_add(avl, box(340), box(118)); - avl = gpr_avl_add(avl, box(271), box(119)); + avl = gpr_avl_add(avl, box(340), box(118), NULL); + avl = gpr_avl_add(avl, box(271), box(119), NULL); avl = remove_int(avl, 206); - avl = gpr_avl_add(avl, box(949), box(121)); - avl = gpr_avl_add(avl, box(927), box(122)); - avl = gpr_avl_add(avl, box(34), box(123)); - avl = gpr_avl_add(avl, box(351), box(124)); + avl = gpr_avl_add(avl, box(949), box(121), NULL); + avl = gpr_avl_add(avl, box(927), box(122), NULL); + avl = gpr_avl_add(avl, box(34), box(123), NULL); + avl = gpr_avl_add(avl, box(351), box(124), NULL); avl = remove_int(avl, 836); - avl = gpr_avl_add(avl, box(825), box(126)); - avl = gpr_avl_add(avl, box(352), box(127)); + avl = gpr_avl_add(avl, box(825), box(126), NULL); + avl = gpr_avl_add(avl, box(352), box(127), NULL); avl = remove_int(avl, 107); avl = remove_int(avl, 101); - avl = gpr_avl_add(avl, box(320), box(130)); - avl = gpr_avl_add(avl, box(3), box(131)); + avl = gpr_avl_add(avl, box(320), box(130), NULL); + avl = gpr_avl_add(avl, box(3), box(131), NULL); avl = remove_int(avl, 998); avl = remove_int(avl, 44); - avl = gpr_avl_add(avl, box(525), box(134)); - avl = gpr_avl_add(avl, box(864), box(135)); - avl = gpr_avl_add(avl, box(863), box(136)); + avl = gpr_avl_add(avl, box(525), box(134), NULL); + avl = gpr_avl_add(avl, box(864), box(135), NULL); + avl = gpr_avl_add(avl, box(863), box(136), NULL); avl = remove_int(avl, 770); - avl = gpr_avl_add(avl, box(440), box(138)); + avl = gpr_avl_add(avl, box(440), box(138), NULL); avl = remove_int(avl, 516); - avl = gpr_avl_add(avl, box(116), box(140)); + avl = gpr_avl_add(avl, box(116), box(140), NULL); avl = remove_int(avl, 380); - avl = gpr_avl_add(avl, box(878), box(142)); + avl = gpr_avl_add(avl, box(878), box(142), NULL); avl = remove_int(avl, 439); - avl = gpr_avl_add(avl, box(994), box(144)); + avl = gpr_avl_add(avl, box(994), box(144), NULL); avl = remove_int(avl, 294); avl = remove_int(avl, 593); - avl = gpr_avl_add(avl, box(696), box(147)); + avl = gpr_avl_add(avl, box(696), box(147), NULL); avl = remove_int(avl, 8); - avl = gpr_avl_add(avl, box(881), box(149)); + avl = gpr_avl_add(avl, box(881), box(149), NULL); avl = remove_int(avl, 32); avl = remove_int(avl, 242); - avl = gpr_avl_add(avl, box(487), box(152)); - avl = gpr_avl_add(avl, box(637), box(153)); - avl = gpr_avl_add(avl, box(793), box(154)); - avl = gpr_avl_add(avl, box(696), box(155)); + avl = gpr_avl_add(avl, box(487), box(152), NULL); + avl = gpr_avl_add(avl, box(637), box(153), NULL); + avl = gpr_avl_add(avl, box(793), box(154), NULL); + avl = gpr_avl_add(avl, box(696), box(155), NULL); avl = remove_int(avl, 458); - avl = gpr_avl_add(avl, box(828), box(157)); + avl = gpr_avl_add(avl, box(828), box(157), NULL); avl = remove_int(avl, 784); avl = remove_int(avl, 274); - avl = gpr_avl_add(avl, box(783), box(160)); + avl = gpr_avl_add(avl, box(783), box(160), NULL); avl = remove_int(avl, 21); - avl = gpr_avl_add(avl, box(866), box(162)); + avl = gpr_avl_add(avl, box(866), box(162), NULL); avl = remove_int(avl, 919); - avl = gpr_avl_add(avl, box(435), box(164)); + avl = gpr_avl_add(avl, box(435), box(164), NULL); avl = remove_int(avl, 385); - avl = gpr_avl_add(avl, box(475), box(166)); + avl = gpr_avl_add(avl, box(475), box(166), NULL); avl = remove_int(avl, 339); - avl = gpr_avl_add(avl, box(615), box(168)); + avl = gpr_avl_add(avl, box(615), box(168), NULL); avl = remove_int(avl, 866); avl = remove_int(avl, 82); avl = remove_int(avl, 271); - avl = gpr_avl_add(avl, box(590), box(172)); - avl = gpr_avl_add(avl, box(852), box(173)); + avl = gpr_avl_add(avl, box(590), box(172), NULL); + avl = gpr_avl_add(avl, box(852), box(173), NULL); avl = remove_int(avl, 318); avl = remove_int(avl, 82); - avl = gpr_avl_add(avl, box(672), box(176)); + avl = gpr_avl_add(avl, box(672), box(176), NULL); avl = remove_int(avl, 430); - avl = gpr_avl_add(avl, box(821), box(178)); - avl = gpr_avl_add(avl, box(365), box(179)); + avl = gpr_avl_add(avl, box(821), box(178), NULL); + avl = gpr_avl_add(avl, box(365), box(179), NULL); avl = remove_int(avl, 78); - avl = gpr_avl_add(avl, box(700), box(181)); - avl = gpr_avl_add(avl, box(353), box(182)); + avl = gpr_avl_add(avl, box(700), box(181), NULL); + avl = gpr_avl_add(avl, box(353), box(182), NULL); avl = remove_int(avl, 492); - avl = gpr_avl_add(avl, box(991), box(184)); + avl = gpr_avl_add(avl, box(991), box(184), NULL); avl = remove_int(avl, 330); - avl = gpr_avl_add(avl, box(873), box(186)); + avl = gpr_avl_add(avl, box(873), box(186), NULL); avl = remove_int(avl, 589); - avl = gpr_avl_add(avl, box(676), box(188)); - avl = gpr_avl_add(avl, box(790), box(189)); + avl = gpr_avl_add(avl, box(676), box(188), NULL); + avl = gpr_avl_add(avl, box(790), box(189), NULL); avl = remove_int(avl, 521); avl = remove_int(avl, 47); - avl = gpr_avl_add(avl, box(976), box(192)); - avl = gpr_avl_add(avl, box(683), box(193)); + avl = gpr_avl_add(avl, box(976), box(192), NULL); + avl = gpr_avl_add(avl, box(683), box(193), NULL); avl = remove_int(avl, 803); avl = remove_int(avl, 1006); - avl = gpr_avl_add(avl, box(775), box(196)); - avl = gpr_avl_add(avl, box(411), box(197)); - avl = gpr_avl_add(avl, box(697), box(198)); + avl = gpr_avl_add(avl, box(775), box(196), NULL); + avl = gpr_avl_add(avl, box(411), box(197), NULL); + avl = gpr_avl_add(avl, box(697), box(198), NULL); avl = remove_int(avl, 50); - avl = gpr_avl_add(avl, box(213), box(200)); + avl = gpr_avl_add(avl, box(213), box(200), NULL); avl = remove_int(avl, 714); - avl = gpr_avl_add(avl, box(981), box(202)); - avl = gpr_avl_add(avl, box(502), box(203)); - avl = gpr_avl_add(avl, box(697), box(204)); - avl = gpr_avl_add(avl, box(603), box(205)); - avl = gpr_avl_add(avl, box(117), box(206)); + avl = gpr_avl_add(avl, box(981), box(202), NULL); + avl = gpr_avl_add(avl, box(502), box(203), NULL); + avl = gpr_avl_add(avl, box(697), box(204), NULL); + avl = gpr_avl_add(avl, box(603), box(205), NULL); + avl = gpr_avl_add(avl, box(117), box(206), NULL); avl = remove_int(avl, 363); - avl = gpr_avl_add(avl, box(104), box(208)); + avl = gpr_avl_add(avl, box(104), box(208), NULL); avl = remove_int(avl, 842); - avl = gpr_avl_add(avl, box(48), box(210)); + avl = gpr_avl_add(avl, box(48), box(210), NULL); avl = remove_int(avl, 764); - avl = gpr_avl_add(avl, box(482), box(212)); - avl = gpr_avl_add(avl, box(928), box(213)); - avl = gpr_avl_add(avl, box(30), box(214)); - avl = gpr_avl_add(avl, box(820), box(215)); - avl = gpr_avl_add(avl, box(334), box(216)); + avl = gpr_avl_add(avl, box(482), box(212), NULL); + avl = gpr_avl_add(avl, box(928), box(213), NULL); + avl = gpr_avl_add(avl, box(30), box(214), NULL); + avl = gpr_avl_add(avl, box(820), box(215), NULL); + avl = gpr_avl_add(avl, box(334), box(216), NULL); avl = remove_int(avl, 306); - avl = gpr_avl_add(avl, box(789), box(218)); + avl = gpr_avl_add(avl, box(789), box(218), NULL); avl = remove_int(avl, 924); - avl = gpr_avl_add(avl, box(53), box(220)); + avl = gpr_avl_add(avl, box(53), box(220), NULL); avl = remove_int(avl, 657); - avl = gpr_avl_add(avl, box(130), box(222)); - avl = gpr_avl_add(avl, box(239), box(223)); + avl = gpr_avl_add(avl, box(130), box(222), NULL); + avl = gpr_avl_add(avl, box(239), box(223), NULL); avl = remove_int(avl, 20); - avl = gpr_avl_add(avl, box(117), box(225)); + avl = gpr_avl_add(avl, box(117), box(225), NULL); avl = remove_int(avl, 882); avl = remove_int(avl, 891); - avl = gpr_avl_add(avl, box(9), box(228)); - avl = gpr_avl_add(avl, box(496), box(229)); - avl = gpr_avl_add(avl, box(750), box(230)); - avl = gpr_avl_add(avl, box(283), box(231)); - avl = gpr_avl_add(avl, box(802), box(232)); + avl = gpr_avl_add(avl, box(9), box(228), NULL); + avl = gpr_avl_add(avl, box(496), box(229), NULL); + avl = gpr_avl_add(avl, box(750), box(230), NULL); + avl = gpr_avl_add(avl, box(283), box(231), NULL); + avl = gpr_avl_add(avl, box(802), box(232), NULL); avl = remove_int(avl, 352); - avl = gpr_avl_add(avl, box(374), box(234)); - avl = gpr_avl_add(avl, box(6), box(235)); - avl = gpr_avl_add(avl, box(756), box(236)); - avl = gpr_avl_add(avl, box(597), box(237)); - avl = gpr_avl_add(avl, box(661), box(238)); + avl = gpr_avl_add(avl, box(374), box(234), NULL); + avl = gpr_avl_add(avl, box(6), box(235), NULL); + avl = gpr_avl_add(avl, box(756), box(236), NULL); + avl = gpr_avl_add(avl, box(597), box(237), NULL); + avl = gpr_avl_add(avl, box(661), box(238), NULL); avl = remove_int(avl, 96); - avl = gpr_avl_add(avl, box(894), box(240)); + avl = gpr_avl_add(avl, box(894), box(240), NULL); avl = remove_int(avl, 749); - avl = gpr_avl_add(avl, box(71), box(242)); + avl = gpr_avl_add(avl, box(71), box(242), NULL); avl = remove_int(avl, 68); - avl = gpr_avl_add(avl, box(388), box(244)); + avl = gpr_avl_add(avl, box(388), box(244), NULL); avl = remove_int(avl, 119); avl = remove_int(avl, 856); - avl = gpr_avl_add(avl, box(176), box(247)); - avl = gpr_avl_add(avl, box(993), box(248)); + avl = gpr_avl_add(avl, box(176), box(247), NULL); + avl = gpr_avl_add(avl, box(993), box(248), NULL); avl = remove_int(avl, 178); avl = remove_int(avl, 781); avl = remove_int(avl, 771); @@ -499,37 +501,37 @@ static void test_badcase2(void) { avl = remove_int(avl, 157); avl = remove_int(avl, 142); avl = remove_int(avl, 686); - avl = gpr_avl_add(avl, box(779), box(257)); - avl = gpr_avl_add(avl, box(484), box(258)); + avl = gpr_avl_add(avl, box(779), box(257), NULL); + avl = gpr_avl_add(avl, box(484), box(258), NULL); avl = remove_int(avl, 837); - avl = gpr_avl_add(avl, box(388), box(260)); + avl = gpr_avl_add(avl, box(388), box(260), NULL); avl = remove_int(avl, 987); - avl = gpr_avl_add(avl, box(336), box(262)); + avl = gpr_avl_add(avl, box(336), box(262), NULL); avl = remove_int(avl, 855); - avl = gpr_avl_add(avl, box(668), box(264)); + avl = gpr_avl_add(avl, box(668), box(264), NULL); avl = remove_int(avl, 648); - avl = gpr_avl_add(avl, box(193), box(266)); + avl = gpr_avl_add(avl, box(193), box(266), NULL); avl = remove_int(avl, 939); - avl = gpr_avl_add(avl, box(740), box(268)); - avl = gpr_avl_add(avl, box(503), box(269)); - avl = gpr_avl_add(avl, box(765), box(270)); + avl = gpr_avl_add(avl, box(740), box(268), NULL); + avl = gpr_avl_add(avl, box(503), box(269), NULL); + avl = gpr_avl_add(avl, box(765), box(270), NULL); avl = remove_int(avl, 924); avl = remove_int(avl, 513); - avl = gpr_avl_add(avl, box(161), box(273)); - avl = gpr_avl_add(avl, box(502), box(274)); - avl = gpr_avl_add(avl, box(846), box(275)); + avl = gpr_avl_add(avl, box(161), box(273), NULL); + avl = gpr_avl_add(avl, box(502), box(274), NULL); + avl = gpr_avl_add(avl, box(846), box(275), NULL); avl = remove_int(avl, 931); - avl = gpr_avl_add(avl, box(87), box(277)); - avl = gpr_avl_add(avl, box(949), box(278)); - avl = gpr_avl_add(avl, box(548), box(279)); - avl = gpr_avl_add(avl, box(951), box(280)); + avl = gpr_avl_add(avl, box(87), box(277), NULL); + avl = gpr_avl_add(avl, box(949), box(278), NULL); + avl = gpr_avl_add(avl, box(548), box(279), NULL); + avl = gpr_avl_add(avl, box(951), box(280), NULL); avl = remove_int(avl, 1018); avl = remove_int(avl, 568); - avl = gpr_avl_add(avl, box(138), box(283)); - avl = gpr_avl_add(avl, box(202), box(284)); - avl = gpr_avl_add(avl, box(157), box(285)); - avl = gpr_avl_add(avl, box(264), box(286)); - avl = gpr_avl_add(avl, box(370), box(287)); + avl = gpr_avl_add(avl, box(138), box(283), NULL); + avl = gpr_avl_add(avl, box(202), box(284), NULL); + avl = gpr_avl_add(avl, box(157), box(285), NULL); + avl = gpr_avl_add(avl, box(264), box(286), NULL); + avl = gpr_avl_add(avl, box(370), box(287), NULL); avl = remove_int(avl, 736); avl = remove_int(avl, 751); avl = remove_int(avl, 506); @@ -537,524 +539,524 @@ static void test_badcase2(void) { avl = remove_int(avl, 358); avl = remove_int(avl, 657); avl = remove_int(avl, 86); - avl = gpr_avl_add(avl, box(876), box(295)); + avl = gpr_avl_add(avl, box(876), box(295), NULL); avl = remove_int(avl, 354); - avl = gpr_avl_add(avl, box(134), box(297)); + avl = gpr_avl_add(avl, box(134), box(297), NULL); avl = remove_int(avl, 781); avl = remove_int(avl, 183); - avl = gpr_avl_add(avl, box(914), box(300)); + avl = gpr_avl_add(avl, box(914), box(300), NULL); avl = remove_int(avl, 926); avl = remove_int(avl, 398); avl = remove_int(avl, 932); avl = remove_int(avl, 804); avl = remove_int(avl, 326); - avl = gpr_avl_add(avl, box(208), box(306)); - avl = gpr_avl_add(avl, box(699), box(307)); + avl = gpr_avl_add(avl, box(208), box(306), NULL); + avl = gpr_avl_add(avl, box(699), box(307), NULL); avl = remove_int(avl, 576); avl = remove_int(avl, 850); avl = remove_int(avl, 514); avl = remove_int(avl, 676); avl = remove_int(avl, 549); avl = remove_int(avl, 767); - avl = gpr_avl_add(avl, box(58), box(314)); - avl = gpr_avl_add(avl, box(265), box(315)); - avl = gpr_avl_add(avl, box(268), box(316)); - avl = gpr_avl_add(avl, box(103), box(317)); - avl = gpr_avl_add(avl, box(440), box(318)); + avl = gpr_avl_add(avl, box(58), box(314), NULL); + avl = gpr_avl_add(avl, box(265), box(315), NULL); + avl = gpr_avl_add(avl, box(268), box(316), NULL); + avl = gpr_avl_add(avl, box(103), box(317), NULL); + avl = gpr_avl_add(avl, box(440), box(318), NULL); avl = remove_int(avl, 777); - avl = gpr_avl_add(avl, box(670), box(320)); + avl = gpr_avl_add(avl, box(670), box(320), NULL); avl = remove_int(avl, 506); avl = remove_int(avl, 487); - avl = gpr_avl_add(avl, box(421), box(323)); + avl = gpr_avl_add(avl, box(421), box(323), NULL); avl = remove_int(avl, 514); - avl = gpr_avl_add(avl, box(701), box(325)); + avl = gpr_avl_add(avl, box(701), box(325), NULL); avl = remove_int(avl, 949); avl = remove_int(avl, 872); avl = remove_int(avl, 139); - avl = gpr_avl_add(avl, box(781), box(329)); - avl = gpr_avl_add(avl, box(543), box(330)); - avl = gpr_avl_add(avl, box(147), box(331)); + avl = gpr_avl_add(avl, box(781), box(329), NULL); + avl = gpr_avl_add(avl, box(543), box(330), NULL); + avl = gpr_avl_add(avl, box(147), box(331), NULL); avl = remove_int(avl, 190); - avl = gpr_avl_add(avl, box(453), box(333)); + avl = gpr_avl_add(avl, box(453), box(333), NULL); avl = remove_int(avl, 262); avl = remove_int(avl, 850); avl = remove_int(avl, 286); avl = remove_int(avl, 787); - avl = gpr_avl_add(avl, box(514), box(338)); + avl = gpr_avl_add(avl, box(514), box(338), NULL); avl = remove_int(avl, 812); - avl = gpr_avl_add(avl, box(431), box(340)); - avl = gpr_avl_add(avl, box(8), box(341)); + avl = gpr_avl_add(avl, box(431), box(340), NULL); + avl = gpr_avl_add(avl, box(8), box(341), NULL); avl = remove_int(avl, 843); - avl = gpr_avl_add(avl, box(831), box(343)); + avl = gpr_avl_add(avl, box(831), box(343), NULL); avl = remove_int(avl, 472); avl = remove_int(avl, 157); - avl = gpr_avl_add(avl, box(612), box(346)); - avl = gpr_avl_add(avl, box(802), box(347)); + avl = gpr_avl_add(avl, box(612), box(346), NULL); + avl = gpr_avl_add(avl, box(802), box(347), NULL); avl = remove_int(avl, 554); - avl = gpr_avl_add(avl, box(409), box(349)); - avl = gpr_avl_add(avl, box(439), box(350)); - avl = gpr_avl_add(avl, box(725), box(351)); - avl = gpr_avl_add(avl, box(568), box(352)); + avl = gpr_avl_add(avl, box(409), box(349), NULL); + avl = gpr_avl_add(avl, box(439), box(350), NULL); + avl = gpr_avl_add(avl, box(725), box(351), NULL); + avl = gpr_avl_add(avl, box(568), box(352), NULL); avl = remove_int(avl, 475); avl = remove_int(avl, 672); avl = remove_int(avl, 62); avl = remove_int(avl, 753); - avl = gpr_avl_add(avl, box(435), box(357)); - avl = gpr_avl_add(avl, box(950), box(358)); - avl = gpr_avl_add(avl, box(532), box(359)); - avl = gpr_avl_add(avl, box(832), box(360)); + avl = gpr_avl_add(avl, box(435), box(357), NULL); + avl = gpr_avl_add(avl, box(950), box(358), NULL); + avl = gpr_avl_add(avl, box(532), box(359), NULL); + avl = gpr_avl_add(avl, box(832), box(360), NULL); avl = remove_int(avl, 390); - avl = gpr_avl_add(avl, box(993), box(362)); + avl = gpr_avl_add(avl, box(993), box(362), NULL); avl = remove_int(avl, 198); avl = remove_int(avl, 401); - avl = gpr_avl_add(avl, box(316), box(365)); + avl = gpr_avl_add(avl, box(316), box(365), NULL); avl = remove_int(avl, 843); - avl = gpr_avl_add(avl, box(541), box(367)); - avl = gpr_avl_add(avl, box(505), box(368)); + avl = gpr_avl_add(avl, box(541), box(367), NULL); + avl = gpr_avl_add(avl, box(505), box(368), NULL); avl = remove_int(avl, 445); avl = remove_int(avl, 256); - avl = gpr_avl_add(avl, box(232), box(371)); + avl = gpr_avl_add(avl, box(232), box(371), NULL); avl = remove_int(avl, 577); avl = remove_int(avl, 558); - avl = gpr_avl_add(avl, box(910), box(374)); + avl = gpr_avl_add(avl, box(910), box(374), NULL); avl = remove_int(avl, 902); avl = remove_int(avl, 755); avl = remove_int(avl, 114); avl = remove_int(avl, 438); avl = remove_int(avl, 224); - avl = gpr_avl_add(avl, box(920), box(380)); - avl = gpr_avl_add(avl, box(655), box(381)); + avl = gpr_avl_add(avl, box(920), box(380), NULL); + avl = gpr_avl_add(avl, box(655), box(381), NULL); avl = remove_int(avl, 557); avl = remove_int(avl, 102); avl = remove_int(avl, 165); - avl = gpr_avl_add(avl, box(191), box(385)); + avl = gpr_avl_add(avl, box(191), box(385), NULL); avl = remove_int(avl, 30); - avl = gpr_avl_add(avl, box(406), box(387)); - avl = gpr_avl_add(avl, box(66), box(388)); - avl = gpr_avl_add(avl, box(87), box(389)); + avl = gpr_avl_add(avl, box(406), box(387), NULL); + avl = gpr_avl_add(avl, box(66), box(388), NULL); + avl = gpr_avl_add(avl, box(87), box(389), NULL); avl = remove_int(avl, 7); avl = remove_int(avl, 671); - avl = gpr_avl_add(avl, box(234), box(392)); + avl = gpr_avl_add(avl, box(234), box(392), NULL); avl = remove_int(avl, 463); - avl = gpr_avl_add(avl, box(75), box(394)); - avl = gpr_avl_add(avl, box(487), box(395)); + avl = gpr_avl_add(avl, box(75), box(394), NULL); + avl = gpr_avl_add(avl, box(487), box(395), NULL); avl = remove_int(avl, 203); - avl = gpr_avl_add(avl, box(711), box(397)); + avl = gpr_avl_add(avl, box(711), box(397), NULL); avl = remove_int(avl, 291); avl = remove_int(avl, 798); avl = remove_int(avl, 337); - avl = gpr_avl_add(avl, box(877), box(401)); - avl = gpr_avl_add(avl, box(388), box(402)); + avl = gpr_avl_add(avl, box(877), box(401), NULL); + avl = gpr_avl_add(avl, box(388), box(402), NULL); avl = remove_int(avl, 975); - avl = gpr_avl_add(avl, box(200), box(404)); - avl = gpr_avl_add(avl, box(408), box(405)); - avl = gpr_avl_add(avl, box(3), box(406)); - avl = gpr_avl_add(avl, box(971), box(407)); + avl = gpr_avl_add(avl, box(200), box(404), NULL); + avl = gpr_avl_add(avl, box(408), box(405), NULL); + avl = gpr_avl_add(avl, box(3), box(406), NULL); + avl = gpr_avl_add(avl, box(971), box(407), NULL); avl = remove_int(avl, 841); avl = remove_int(avl, 910); avl = remove_int(avl, 74); avl = remove_int(avl, 888); - avl = gpr_avl_add(avl, box(492), box(412)); + avl = gpr_avl_add(avl, box(492), box(412), NULL); avl = remove_int(avl, 14); avl = remove_int(avl, 364); - avl = gpr_avl_add(avl, box(215), box(415)); + avl = gpr_avl_add(avl, box(215), box(415), NULL); avl = remove_int(avl, 778); avl = remove_int(avl, 45); - avl = gpr_avl_add(avl, box(328), box(418)); - avl = gpr_avl_add(avl, box(597), box(419)); + avl = gpr_avl_add(avl, box(328), box(418), NULL); + avl = gpr_avl_add(avl, box(597), box(419), NULL); avl = remove_int(avl, 34); - avl = gpr_avl_add(avl, box(736), box(421)); + avl = gpr_avl_add(avl, box(736), box(421), NULL); avl = remove_int(avl, 37); - avl = gpr_avl_add(avl, box(275), box(423)); - avl = gpr_avl_add(avl, box(70), box(424)); - avl = gpr_avl_add(avl, box(771), box(425)); + avl = gpr_avl_add(avl, box(275), box(423), NULL); + avl = gpr_avl_add(avl, box(70), box(424), NULL); + avl = gpr_avl_add(avl, box(771), box(425), NULL); avl = remove_int(avl, 536); avl = remove_int(avl, 421); - avl = gpr_avl_add(avl, box(186), box(428)); - avl = gpr_avl_add(avl, box(788), box(429)); - avl = gpr_avl_add(avl, box(224), box(430)); + avl = gpr_avl_add(avl, box(186), box(428), NULL); + avl = gpr_avl_add(avl, box(788), box(429), NULL); + avl = gpr_avl_add(avl, box(224), box(430), NULL); avl = remove_int(avl, 228); - avl = gpr_avl_add(avl, box(48), box(432)); - avl = gpr_avl_add(avl, box(120), box(433)); - avl = gpr_avl_add(avl, box(269), box(434)); - avl = gpr_avl_add(avl, box(904), box(435)); + avl = gpr_avl_add(avl, box(48), box(432), NULL); + avl = gpr_avl_add(avl, box(120), box(433), NULL); + avl = gpr_avl_add(avl, box(269), box(434), NULL); + avl = gpr_avl_add(avl, box(904), box(435), NULL); avl = remove_int(avl, 699); - avl = gpr_avl_add(avl, box(340), box(437)); + avl = gpr_avl_add(avl, box(340), box(437), NULL); avl = remove_int(avl, 276); - avl = gpr_avl_add(avl, box(591), box(439)); - avl = gpr_avl_add(avl, box(778), box(440)); + avl = gpr_avl_add(avl, box(591), box(439), NULL); + avl = gpr_avl_add(avl, box(778), box(440), NULL); avl = remove_int(avl, 490); avl = remove_int(avl, 973); - avl = gpr_avl_add(avl, box(294), box(443)); - avl = gpr_avl_add(avl, box(323), box(444)); + avl = gpr_avl_add(avl, box(294), box(443), NULL); + avl = gpr_avl_add(avl, box(323), box(444), NULL); avl = remove_int(avl, 685); - avl = gpr_avl_add(avl, box(38), box(446)); - avl = gpr_avl_add(avl, box(525), box(447)); + avl = gpr_avl_add(avl, box(38), box(446), NULL); + avl = gpr_avl_add(avl, box(525), box(447), NULL); avl = remove_int(avl, 162); - avl = gpr_avl_add(avl, box(462), box(449)); - avl = gpr_avl_add(avl, box(340), box(450)); + avl = gpr_avl_add(avl, box(462), box(449), NULL); + avl = gpr_avl_add(avl, box(340), box(450), NULL); avl = remove_int(avl, 734); avl = remove_int(avl, 959); - avl = gpr_avl_add(avl, box(752), box(453)); - avl = gpr_avl_add(avl, box(667), box(454)); + avl = gpr_avl_add(avl, box(752), box(453), NULL); + avl = gpr_avl_add(avl, box(667), box(454), NULL); avl = remove_int(avl, 558); avl = remove_int(avl, 657); - avl = gpr_avl_add(avl, box(711), box(457)); + avl = gpr_avl_add(avl, box(711), box(457), NULL); avl = remove_int(avl, 937); - avl = gpr_avl_add(avl, box(741), box(459)); - avl = gpr_avl_add(avl, box(40), box(460)); + avl = gpr_avl_add(avl, box(741), box(459), NULL); + avl = gpr_avl_add(avl, box(40), box(460), NULL); avl = remove_int(avl, 784); - avl = gpr_avl_add(avl, box(292), box(462)); + avl = gpr_avl_add(avl, box(292), box(462), NULL); avl = remove_int(avl, 164); avl = remove_int(avl, 931); avl = remove_int(avl, 886); - avl = gpr_avl_add(avl, box(968), box(466)); + avl = gpr_avl_add(avl, box(968), box(466), NULL); avl = remove_int(avl, 263); - avl = gpr_avl_add(avl, box(647), box(468)); - avl = gpr_avl_add(avl, box(92), box(469)); + avl = gpr_avl_add(avl, box(647), box(468), NULL); + avl = gpr_avl_add(avl, box(92), box(469), NULL); avl = remove_int(avl, 310); - avl = gpr_avl_add(avl, box(711), box(471)); - avl = gpr_avl_add(avl, box(675), box(472)); + avl = gpr_avl_add(avl, box(711), box(471), NULL); + avl = gpr_avl_add(avl, box(675), box(472), NULL); avl = remove_int(avl, 549); - avl = gpr_avl_add(avl, box(380), box(474)); + avl = gpr_avl_add(avl, box(380), box(474), NULL); avl = remove_int(avl, 825); - avl = gpr_avl_add(avl, box(668), box(476)); + avl = gpr_avl_add(avl, box(668), box(476), NULL); avl = remove_int(avl, 498); - avl = gpr_avl_add(avl, box(870), box(478)); - avl = gpr_avl_add(avl, box(391), box(479)); - avl = gpr_avl_add(avl, box(264), box(480)); + avl = gpr_avl_add(avl, box(870), box(478), NULL); + avl = gpr_avl_add(avl, box(391), box(479), NULL); + avl = gpr_avl_add(avl, box(264), box(480), NULL); avl = remove_int(avl, 1); avl = remove_int(avl, 849); avl = remove_int(avl, 88); avl = remove_int(avl, 255); avl = remove_int(avl, 763); avl = remove_int(avl, 831); - avl = gpr_avl_add(avl, box(508), box(487)); + avl = gpr_avl_add(avl, box(508), box(487), NULL); avl = remove_int(avl, 849); avl = remove_int(avl, 47); - avl = gpr_avl_add(avl, box(299), box(490)); + avl = gpr_avl_add(avl, box(299), box(490), NULL); avl = remove_int(avl, 625); avl = remove_int(avl, 433); avl = remove_int(avl, 904); avl = remove_int(avl, 761); - avl = gpr_avl_add(avl, box(33), box(495)); - avl = gpr_avl_add(avl, box(524), box(496)); + avl = gpr_avl_add(avl, box(33), box(495), NULL); + avl = gpr_avl_add(avl, box(524), box(496), NULL); avl = remove_int(avl, 210); avl = remove_int(avl, 299); - avl = gpr_avl_add(avl, box(823), box(499)); + avl = gpr_avl_add(avl, box(823), box(499), NULL); avl = remove_int(avl, 479); avl = remove_int(avl, 96); avl = remove_int(avl, 1013); - avl = gpr_avl_add(avl, box(768), box(503)); + avl = gpr_avl_add(avl, box(768), box(503), NULL); avl = remove_int(avl, 638); avl = remove_int(avl, 20); - avl = gpr_avl_add(avl, box(663), box(506)); + avl = gpr_avl_add(avl, box(663), box(506), NULL); avl = remove_int(avl, 882); - avl = gpr_avl_add(avl, box(745), box(508)); + avl = gpr_avl_add(avl, box(745), box(508), NULL); avl = remove_int(avl, 352); - avl = gpr_avl_add(avl, box(10), box(510)); + avl = gpr_avl_add(avl, box(10), box(510), NULL); avl = remove_int(avl, 484); - avl = gpr_avl_add(avl, box(420), box(512)); - avl = gpr_avl_add(avl, box(884), box(513)); - avl = gpr_avl_add(avl, box(993), box(514)); - avl = gpr_avl_add(avl, box(251), box(515)); + avl = gpr_avl_add(avl, box(420), box(512), NULL); + avl = gpr_avl_add(avl, box(884), box(513), NULL); + avl = gpr_avl_add(avl, box(993), box(514), NULL); + avl = gpr_avl_add(avl, box(251), box(515), NULL); avl = remove_int(avl, 222); - avl = gpr_avl_add(avl, box(734), box(517)); - avl = gpr_avl_add(avl, box(952), box(518)); + avl = gpr_avl_add(avl, box(734), box(517), NULL); + avl = gpr_avl_add(avl, box(952), box(518), NULL); avl = remove_int(avl, 26); avl = remove_int(avl, 270); avl = remove_int(avl, 481); avl = remove_int(avl, 693); avl = remove_int(avl, 1006); - avl = gpr_avl_add(avl, box(77), box(524)); + avl = gpr_avl_add(avl, box(77), box(524), NULL); avl = remove_int(avl, 897); - avl = gpr_avl_add(avl, box(719), box(526)); - avl = gpr_avl_add(avl, box(622), box(527)); + avl = gpr_avl_add(avl, box(719), box(526), NULL); + avl = gpr_avl_add(avl, box(622), box(527), NULL); avl = remove_int(avl, 28); avl = remove_int(avl, 836); avl = remove_int(avl, 142); - avl = gpr_avl_add(avl, box(445), box(531)); - avl = gpr_avl_add(avl, box(410), box(532)); + avl = gpr_avl_add(avl, box(445), box(531), NULL); + avl = gpr_avl_add(avl, box(410), box(532), NULL); avl = remove_int(avl, 575); - avl = gpr_avl_add(avl, box(634), box(534)); - avl = gpr_avl_add(avl, box(906), box(535)); + avl = gpr_avl_add(avl, box(634), box(534), NULL); + avl = gpr_avl_add(avl, box(906), box(535), NULL); avl = remove_int(avl, 649); - avl = gpr_avl_add(avl, box(813), box(537)); + avl = gpr_avl_add(avl, box(813), box(537), NULL); avl = remove_int(avl, 702); avl = remove_int(avl, 732); - avl = gpr_avl_add(avl, box(105), box(540)); - avl = gpr_avl_add(avl, box(867), box(541)); + avl = gpr_avl_add(avl, box(105), box(540), NULL); + avl = gpr_avl_add(avl, box(867), box(541), NULL); avl = remove_int(avl, 964); avl = remove_int(avl, 941); - avl = gpr_avl_add(avl, box(947), box(544)); + avl = gpr_avl_add(avl, box(947), box(544), NULL); avl = remove_int(avl, 990); - avl = gpr_avl_add(avl, box(816), box(546)); + avl = gpr_avl_add(avl, box(816), box(546), NULL); avl = remove_int(avl, 429); avl = remove_int(avl, 567); avl = remove_int(avl, 541); avl = remove_int(avl, 583); - avl = gpr_avl_add(avl, box(57), box(551)); - avl = gpr_avl_add(avl, box(786), box(552)); - avl = gpr_avl_add(avl, box(526), box(553)); + avl = gpr_avl_add(avl, box(57), box(551), NULL); + avl = gpr_avl_add(avl, box(786), box(552), NULL); + avl = gpr_avl_add(avl, box(526), box(553), NULL); avl = remove_int(avl, 642); avl = remove_int(avl, 220); avl = remove_int(avl, 840); avl = remove_int(avl, 548); - avl = gpr_avl_add(avl, box(528), box(558)); - avl = gpr_avl_add(avl, box(749), box(559)); - avl = gpr_avl_add(avl, box(194), box(560)); + avl = gpr_avl_add(avl, box(528), box(558), NULL); + avl = gpr_avl_add(avl, box(749), box(559), NULL); + avl = gpr_avl_add(avl, box(194), box(560), NULL); avl = remove_int(avl, 517); - avl = gpr_avl_add(avl, box(102), box(562)); + avl = gpr_avl_add(avl, box(102), box(562), NULL); avl = remove_int(avl, 189); - avl = gpr_avl_add(avl, box(927), box(564)); + avl = gpr_avl_add(avl, box(927), box(564), NULL); avl = remove_int(avl, 846); avl = remove_int(avl, 130); - avl = gpr_avl_add(avl, box(694), box(567)); + avl = gpr_avl_add(avl, box(694), box(567), NULL); avl = remove_int(avl, 750); - avl = gpr_avl_add(avl, box(357), box(569)); + avl = gpr_avl_add(avl, box(357), box(569), NULL); avl = remove_int(avl, 431); avl = remove_int(avl, 91); - avl = gpr_avl_add(avl, box(640), box(572)); + avl = gpr_avl_add(avl, box(640), box(572), NULL); avl = remove_int(avl, 4); - avl = gpr_avl_add(avl, box(81), box(574)); - avl = gpr_avl_add(avl, box(595), box(575)); + avl = gpr_avl_add(avl, box(81), box(574), NULL); + avl = gpr_avl_add(avl, box(595), box(575), NULL); avl = remove_int(avl, 444); avl = remove_int(avl, 262); avl = remove_int(avl, 11); - avl = gpr_avl_add(avl, box(192), box(579)); - avl = gpr_avl_add(avl, box(158), box(580)); + avl = gpr_avl_add(avl, box(192), box(579), NULL); + avl = gpr_avl_add(avl, box(158), box(580), NULL); avl = remove_int(avl, 401); avl = remove_int(avl, 918); - avl = gpr_avl_add(avl, box(180), box(583)); + avl = gpr_avl_add(avl, box(180), box(583), NULL); avl = remove_int(avl, 268); - avl = gpr_avl_add(avl, box(1012), box(585)); - avl = gpr_avl_add(avl, box(90), box(586)); - avl = gpr_avl_add(avl, box(946), box(587)); + avl = gpr_avl_add(avl, box(1012), box(585), NULL); + avl = gpr_avl_add(avl, box(90), box(586), NULL); + avl = gpr_avl_add(avl, box(946), box(587), NULL); avl = remove_int(avl, 719); - avl = gpr_avl_add(avl, box(874), box(589)); - avl = gpr_avl_add(avl, box(679), box(590)); + avl = gpr_avl_add(avl, box(874), box(589), NULL); + avl = gpr_avl_add(avl, box(679), box(590), NULL); avl = remove_int(avl, 53); avl = remove_int(avl, 534); - avl = gpr_avl_add(avl, box(646), box(593)); - avl = gpr_avl_add(avl, box(767), box(594)); - avl = gpr_avl_add(avl, box(460), box(595)); - avl = gpr_avl_add(avl, box(852), box(596)); - avl = gpr_avl_add(avl, box(189), box(597)); + avl = gpr_avl_add(avl, box(646), box(593), NULL); + avl = gpr_avl_add(avl, box(767), box(594), NULL); + avl = gpr_avl_add(avl, box(460), box(595), NULL); + avl = gpr_avl_add(avl, box(852), box(596), NULL); + avl = gpr_avl_add(avl, box(189), box(597), NULL); avl = remove_int(avl, 932); avl = remove_int(avl, 366); avl = remove_int(avl, 907); - avl = gpr_avl_add(avl, box(875), box(601)); - avl = gpr_avl_add(avl, box(434), box(602)); - avl = gpr_avl_add(avl, box(704), box(603)); - avl = gpr_avl_add(avl, box(724), box(604)); - avl = gpr_avl_add(avl, box(930), box(605)); - avl = gpr_avl_add(avl, box(1000), box(606)); + avl = gpr_avl_add(avl, box(875), box(601), NULL); + avl = gpr_avl_add(avl, box(434), box(602), NULL); + avl = gpr_avl_add(avl, box(704), box(603), NULL); + avl = gpr_avl_add(avl, box(724), box(604), NULL); + avl = gpr_avl_add(avl, box(930), box(605), NULL); + avl = gpr_avl_add(avl, box(1000), box(606), NULL); avl = remove_int(avl, 479); - avl = gpr_avl_add(avl, box(275), box(608)); + avl = gpr_avl_add(avl, box(275), box(608), NULL); avl = remove_int(avl, 32); - avl = gpr_avl_add(avl, box(939), box(610)); + avl = gpr_avl_add(avl, box(939), box(610), NULL); avl = remove_int(avl, 943); avl = remove_int(avl, 329); - avl = gpr_avl_add(avl, box(490), box(613)); + avl = gpr_avl_add(avl, box(490), box(613), NULL); avl = remove_int(avl, 477); avl = remove_int(avl, 414); avl = remove_int(avl, 187); avl = remove_int(avl, 334); - avl = gpr_avl_add(avl, box(40), box(618)); + avl = gpr_avl_add(avl, box(40), box(618), NULL); avl = remove_int(avl, 751); - avl = gpr_avl_add(avl, box(568), box(620)); - avl = gpr_avl_add(avl, box(120), box(621)); - avl = gpr_avl_add(avl, box(617), box(622)); - avl = gpr_avl_add(avl, box(32), box(623)); + avl = gpr_avl_add(avl, box(568), box(620), NULL); + avl = gpr_avl_add(avl, box(120), box(621), NULL); + avl = gpr_avl_add(avl, box(617), box(622), NULL); + avl = gpr_avl_add(avl, box(32), box(623), NULL); avl = remove_int(avl, 701); - avl = gpr_avl_add(avl, box(910), box(625)); + avl = gpr_avl_add(avl, box(910), box(625), NULL); avl = remove_int(avl, 557); avl = remove_int(avl, 361); avl = remove_int(avl, 937); avl = remove_int(avl, 100); avl = remove_int(avl, 684); - avl = gpr_avl_add(avl, box(751), box(631)); + avl = gpr_avl_add(avl, box(751), box(631), NULL); avl = remove_int(avl, 781); avl = remove_int(avl, 469); avl = remove_int(avl, 75); avl = remove_int(avl, 561); - avl = gpr_avl_add(avl, box(854), box(636)); + avl = gpr_avl_add(avl, box(854), box(636), NULL); avl = remove_int(avl, 164); avl = remove_int(avl, 258); avl = remove_int(avl, 315); avl = remove_int(avl, 261); - avl = gpr_avl_add(avl, box(552), box(641)); - avl = gpr_avl_add(avl, box(6), box(642)); - avl = gpr_avl_add(avl, box(680), box(643)); + avl = gpr_avl_add(avl, box(552), box(641), NULL); + avl = gpr_avl_add(avl, box(6), box(642), NULL); + avl = gpr_avl_add(avl, box(680), box(643), NULL); avl = remove_int(avl, 741); avl = remove_int(avl, 309); avl = remove_int(avl, 272); - avl = gpr_avl_add(avl, box(249), box(647)); + avl = gpr_avl_add(avl, box(249), box(647), NULL); avl = remove_int(avl, 97); avl = remove_int(avl, 850); - avl = gpr_avl_add(avl, box(915), box(650)); - avl = gpr_avl_add(avl, box(816), box(651)); - avl = gpr_avl_add(avl, box(45), box(652)); - avl = gpr_avl_add(avl, box(168), box(653)); + avl = gpr_avl_add(avl, box(915), box(650), NULL); + avl = gpr_avl_add(avl, box(816), box(651), NULL); + avl = gpr_avl_add(avl, box(45), box(652), NULL); + avl = gpr_avl_add(avl, box(168), box(653), NULL); avl = remove_int(avl, 153); avl = remove_int(avl, 239); - avl = gpr_avl_add(avl, box(684), box(656)); - avl = gpr_avl_add(avl, box(208), box(657)); - avl = gpr_avl_add(avl, box(681), box(658)); - avl = gpr_avl_add(avl, box(609), box(659)); - avl = gpr_avl_add(avl, box(645), box(660)); + avl = gpr_avl_add(avl, box(684), box(656), NULL); + avl = gpr_avl_add(avl, box(208), box(657), NULL); + avl = gpr_avl_add(avl, box(681), box(658), NULL); + avl = gpr_avl_add(avl, box(609), box(659), NULL); + avl = gpr_avl_add(avl, box(645), box(660), NULL); avl = remove_int(avl, 799); - avl = gpr_avl_add(avl, box(955), box(662)); - avl = gpr_avl_add(avl, box(946), box(663)); - avl = gpr_avl_add(avl, box(744), box(664)); - avl = gpr_avl_add(avl, box(201), box(665)); - avl = gpr_avl_add(avl, box(136), box(666)); + avl = gpr_avl_add(avl, box(955), box(662), NULL); + avl = gpr_avl_add(avl, box(946), box(663), NULL); + avl = gpr_avl_add(avl, box(744), box(664), NULL); + avl = gpr_avl_add(avl, box(201), box(665), NULL); + avl = gpr_avl_add(avl, box(136), box(666), NULL); avl = remove_int(avl, 357); - avl = gpr_avl_add(avl, box(974), box(668)); + avl = gpr_avl_add(avl, box(974), box(668), NULL); avl = remove_int(avl, 485); - avl = gpr_avl_add(avl, box(1009), box(670)); - avl = gpr_avl_add(avl, box(517), box(671)); + avl = gpr_avl_add(avl, box(1009), box(670), NULL); + avl = gpr_avl_add(avl, box(517), box(671), NULL); avl = remove_int(avl, 491); - avl = gpr_avl_add(avl, box(336), box(673)); - avl = gpr_avl_add(avl, box(589), box(674)); + avl = gpr_avl_add(avl, box(336), box(673), NULL); + avl = gpr_avl_add(avl, box(589), box(674), NULL); avl = remove_int(avl, 546); avl = remove_int(avl, 840); avl = remove_int(avl, 104); avl = remove_int(avl, 347); - avl = gpr_avl_add(avl, box(801), box(679)); + avl = gpr_avl_add(avl, box(801), box(679), NULL); avl = remove_int(avl, 799); avl = remove_int(avl, 702); avl = remove_int(avl, 996); avl = remove_int(avl, 93); - avl = gpr_avl_add(avl, box(561), box(684)); - avl = gpr_avl_add(avl, box(25), box(685)); + avl = gpr_avl_add(avl, box(561), box(684), NULL); + avl = gpr_avl_add(avl, box(25), box(685), NULL); avl = remove_int(avl, 278); - avl = gpr_avl_add(avl, box(191), box(687)); + avl = gpr_avl_add(avl, box(191), box(687), NULL); avl = remove_int(avl, 243); avl = remove_int(avl, 918); avl = remove_int(avl, 449); - avl = gpr_avl_add(avl, box(19), box(691)); - avl = gpr_avl_add(avl, box(762), box(692)); - avl = gpr_avl_add(avl, box(13), box(693)); - avl = gpr_avl_add(avl, box(151), box(694)); - avl = gpr_avl_add(avl, box(152), box(695)); - avl = gpr_avl_add(avl, box(793), box(696)); + avl = gpr_avl_add(avl, box(19), box(691), NULL); + avl = gpr_avl_add(avl, box(762), box(692), NULL); + avl = gpr_avl_add(avl, box(13), box(693), NULL); + avl = gpr_avl_add(avl, box(151), box(694), NULL); + avl = gpr_avl_add(avl, box(152), box(695), NULL); + avl = gpr_avl_add(avl, box(793), box(696), NULL); avl = remove_int(avl, 862); avl = remove_int(avl, 890); - avl = gpr_avl_add(avl, box(687), box(699)); - avl = gpr_avl_add(avl, box(509), box(700)); - avl = gpr_avl_add(avl, box(973), box(701)); + avl = gpr_avl_add(avl, box(687), box(699), NULL); + avl = gpr_avl_add(avl, box(509), box(700), NULL); + avl = gpr_avl_add(avl, box(973), box(701), NULL); avl = remove_int(avl, 230); - avl = gpr_avl_add(avl, box(532), box(703)); + avl = gpr_avl_add(avl, box(532), box(703), NULL); avl = remove_int(avl, 668); - avl = gpr_avl_add(avl, box(281), box(705)); - avl = gpr_avl_add(avl, box(867), box(706)); - avl = gpr_avl_add(avl, box(359), box(707)); + avl = gpr_avl_add(avl, box(281), box(705), NULL); + avl = gpr_avl_add(avl, box(867), box(706), NULL); + avl = gpr_avl_add(avl, box(359), box(707), NULL); avl = remove_int(avl, 425); - avl = gpr_avl_add(avl, box(691), box(709)); - avl = gpr_avl_add(avl, box(163), box(710)); - avl = gpr_avl_add(avl, box(502), box(711)); + avl = gpr_avl_add(avl, box(691), box(709), NULL); + avl = gpr_avl_add(avl, box(163), box(710), NULL); + avl = gpr_avl_add(avl, box(502), box(711), NULL); avl = remove_int(avl, 674); - avl = gpr_avl_add(avl, box(697), box(713)); + avl = gpr_avl_add(avl, box(697), box(713), NULL); avl = remove_int(avl, 271); - avl = gpr_avl_add(avl, box(968), box(715)); - avl = gpr_avl_add(avl, box(48), box(716)); + avl = gpr_avl_add(avl, box(968), box(715), NULL); + avl = gpr_avl_add(avl, box(48), box(716), NULL); avl = remove_int(avl, 543); - avl = gpr_avl_add(avl, box(35), box(718)); - avl = gpr_avl_add(avl, box(751), box(719)); - avl = gpr_avl_add(avl, box(478), box(720)); + avl = gpr_avl_add(avl, box(35), box(718), NULL); + avl = gpr_avl_add(avl, box(751), box(719), NULL); + avl = gpr_avl_add(avl, box(478), box(720), NULL); avl = remove_int(avl, 797); avl = remove_int(avl, 309); - avl = gpr_avl_add(avl, box(927), box(723)); + avl = gpr_avl_add(avl, box(927), box(723), NULL); avl = remove_int(avl, 504); - avl = gpr_avl_add(avl, box(286), box(725)); - avl = gpr_avl_add(avl, box(413), box(726)); - avl = gpr_avl_add(avl, box(599), box(727)); + avl = gpr_avl_add(avl, box(286), box(725), NULL); + avl = gpr_avl_add(avl, box(413), box(726), NULL); + avl = gpr_avl_add(avl, box(599), box(727), NULL); avl = remove_int(avl, 105); avl = remove_int(avl, 605); - avl = gpr_avl_add(avl, box(632), box(730)); - avl = gpr_avl_add(avl, box(133), box(731)); + avl = gpr_avl_add(avl, box(632), box(730), NULL); + avl = gpr_avl_add(avl, box(133), box(731), NULL); avl = remove_int(avl, 443); - avl = gpr_avl_add(avl, box(958), box(733)); - avl = gpr_avl_add(avl, box(729), box(734)); + avl = gpr_avl_add(avl, box(958), box(733), NULL); + avl = gpr_avl_add(avl, box(729), box(734), NULL); avl = remove_int(avl, 158); - avl = gpr_avl_add(avl, box(694), box(736)); - avl = gpr_avl_add(avl, box(505), box(737)); + avl = gpr_avl_add(avl, box(694), box(736), NULL); + avl = gpr_avl_add(avl, box(505), box(737), NULL); avl = remove_int(avl, 63); avl = remove_int(avl, 714); - avl = gpr_avl_add(avl, box(1002), box(740)); + avl = gpr_avl_add(avl, box(1002), box(740), NULL); avl = remove_int(avl, 211); - avl = gpr_avl_add(avl, box(765), box(742)); - avl = gpr_avl_add(avl, box(455), box(743)); + avl = gpr_avl_add(avl, box(765), box(742), NULL); + avl = gpr_avl_add(avl, box(455), box(743), NULL); avl = remove_int(avl, 59); avl = remove_int(avl, 224); - avl = gpr_avl_add(avl, box(586), box(746)); - avl = gpr_avl_add(avl, box(348), box(747)); + avl = gpr_avl_add(avl, box(586), box(746), NULL); + avl = gpr_avl_add(avl, box(348), box(747), NULL); avl = remove_int(avl, 10); avl = remove_int(avl, 484); - avl = gpr_avl_add(avl, box(968), box(750)); - avl = gpr_avl_add(avl, box(923), box(751)); + avl = gpr_avl_add(avl, box(968), box(750), NULL); + avl = gpr_avl_add(avl, box(923), box(751), NULL); avl = remove_int(avl, 573); avl = remove_int(avl, 617); - avl = gpr_avl_add(avl, box(812), box(754)); - avl = gpr_avl_add(avl, box(179), box(755)); + avl = gpr_avl_add(avl, box(812), box(754), NULL); + avl = gpr_avl_add(avl, box(179), box(755), NULL); avl = remove_int(avl, 284); avl = remove_int(avl, 157); avl = remove_int(avl, 177); avl = remove_int(avl, 896); - avl = gpr_avl_add(avl, box(649), box(760)); - avl = gpr_avl_add(avl, box(927), box(761)); - avl = gpr_avl_add(avl, box(454), box(762)); - avl = gpr_avl_add(avl, box(217), box(763)); + avl = gpr_avl_add(avl, box(649), box(760), NULL); + avl = gpr_avl_add(avl, box(927), box(761), NULL); + avl = gpr_avl_add(avl, box(454), box(762), NULL); + avl = gpr_avl_add(avl, box(217), box(763), NULL); avl = remove_int(avl, 534); - avl = gpr_avl_add(avl, box(180), box(765)); - avl = gpr_avl_add(avl, box(319), box(766)); + avl = gpr_avl_add(avl, box(180), box(765), NULL); + avl = gpr_avl_add(avl, box(319), box(766), NULL); avl = remove_int(avl, 92); - avl = gpr_avl_add(avl, box(483), box(768)); + avl = gpr_avl_add(avl, box(483), box(768), NULL); avl = remove_int(avl, 504); avl = remove_int(avl, 1017); avl = remove_int(avl, 37); avl = remove_int(avl, 50); - avl = gpr_avl_add(avl, box(302), box(773)); + avl = gpr_avl_add(avl, box(302), box(773), NULL); avl = remove_int(avl, 807); - avl = gpr_avl_add(avl, box(463), box(775)); - avl = gpr_avl_add(avl, box(271), box(776)); - avl = gpr_avl_add(avl, box(644), box(777)); + avl = gpr_avl_add(avl, box(463), box(775), NULL); + avl = gpr_avl_add(avl, box(271), box(776), NULL); + avl = gpr_avl_add(avl, box(644), box(777), NULL); avl = remove_int(avl, 618); - avl = gpr_avl_add(avl, box(166), box(779)); - avl = gpr_avl_add(avl, box(538), box(780)); + avl = gpr_avl_add(avl, box(166), box(779), NULL); + avl = gpr_avl_add(avl, box(538), box(780), NULL); avl = remove_int(avl, 606); - avl = gpr_avl_add(avl, box(425), box(782)); + avl = gpr_avl_add(avl, box(425), box(782), NULL); avl = remove_int(avl, 725); avl = remove_int(avl, 383); - avl = gpr_avl_add(avl, box(155), box(785)); + avl = gpr_avl_add(avl, box(155), box(785), NULL); avl = remove_int(avl, 889); - avl = gpr_avl_add(avl, box(653), box(787)); + avl = gpr_avl_add(avl, box(653), box(787), NULL); avl = remove_int(avl, 386); - avl = gpr_avl_add(avl, box(142), box(789)); + avl = gpr_avl_add(avl, box(142), box(789), NULL); avl = remove_int(avl, 107); avl = remove_int(avl, 603); avl = remove_int(avl, 971); - avl = gpr_avl_add(avl, box(80), box(793)); - avl = gpr_avl_add(avl, box(61), box(794)); - avl = gpr_avl_add(avl, box(693), box(795)); - avl = gpr_avl_add(avl, box(592), box(796)); - avl = gpr_avl_add(avl, box(433), box(797)); - avl = gpr_avl_add(avl, box(973), box(798)); + avl = gpr_avl_add(avl, box(80), box(793), NULL); + avl = gpr_avl_add(avl, box(61), box(794), NULL); + avl = gpr_avl_add(avl, box(693), box(795), NULL); + avl = gpr_avl_add(avl, box(592), box(796), NULL); + avl = gpr_avl_add(avl, box(433), box(797), NULL); + avl = gpr_avl_add(avl, box(973), box(798), NULL); avl = remove_int(avl, 901); avl = remove_int(avl, 340); avl = remove_int(avl, 709); - avl = gpr_avl_add(avl, box(224), box(802)); + avl = gpr_avl_add(avl, box(224), box(802), NULL); avl = remove_int(avl, 120); avl = remove_int(avl, 271); - avl = gpr_avl_add(avl, box(780), box(805)); - avl = gpr_avl_add(avl, box(867), box(806)); - avl = gpr_avl_add(avl, box(756), box(807)); - avl = gpr_avl_add(avl, box(583), box(808)); - avl = gpr_avl_add(avl, box(356), box(809)); - avl = gpr_avl_add(avl, box(58), box(810)); + avl = gpr_avl_add(avl, box(780), box(805), NULL); + avl = gpr_avl_add(avl, box(867), box(806), NULL); + avl = gpr_avl_add(avl, box(756), box(807), NULL); + avl = gpr_avl_add(avl, box(583), box(808), NULL); + avl = gpr_avl_add(avl, box(356), box(809), NULL); + avl = gpr_avl_add(avl, box(58), box(810), NULL); avl = remove_int(avl, 219); - avl = gpr_avl_add(avl, box(301), box(812)); + avl = gpr_avl_add(avl, box(301), box(812), NULL); avl = remove_int(avl, 643); avl = remove_int(avl, 787); avl = remove_int(avl, 583); @@ -1063,72 +1065,72 @@ static void test_badcase2(void) { avl = remove_int(avl, 608); avl = remove_int(avl, 363); avl = remove_int(avl, 690); - avl = gpr_avl_add(avl, box(233), box(821)); - avl = gpr_avl_add(avl, box(479), box(822)); - avl = gpr_avl_add(avl, box(323), box(823)); - avl = gpr_avl_add(avl, box(802), box(824)); + avl = gpr_avl_add(avl, box(233), box(821), NULL); + avl = gpr_avl_add(avl, box(479), box(822), NULL); + avl = gpr_avl_add(avl, box(323), box(823), NULL); + avl = gpr_avl_add(avl, box(802), box(824), NULL); avl = remove_int(avl, 682); avl = remove_int(avl, 705); avl = remove_int(avl, 487); - avl = gpr_avl_add(avl, box(530), box(828)); - avl = gpr_avl_add(avl, box(232), box(829)); + avl = gpr_avl_add(avl, box(530), box(828), NULL); + avl = gpr_avl_add(avl, box(232), box(829), NULL); avl = remove_int(avl, 627); - avl = gpr_avl_add(avl, box(396), box(831)); - avl = gpr_avl_add(avl, box(61), box(832)); - avl = gpr_avl_add(avl, box(932), box(833)); - avl = gpr_avl_add(avl, box(108), box(834)); - avl = gpr_avl_add(avl, box(524), box(835)); + avl = gpr_avl_add(avl, box(396), box(831), NULL); + avl = gpr_avl_add(avl, box(61), box(832), NULL); + avl = gpr_avl_add(avl, box(932), box(833), NULL); + avl = gpr_avl_add(avl, box(108), box(834), NULL); + avl = gpr_avl_add(avl, box(524), box(835), NULL); avl = remove_int(avl, 390); avl = remove_int(avl, 307); - avl = gpr_avl_add(avl, box(722), box(838)); - avl = gpr_avl_add(avl, box(907), box(839)); + avl = gpr_avl_add(avl, box(722), box(838), NULL); + avl = gpr_avl_add(avl, box(907), box(839), NULL); avl = remove_int(avl, 286); avl = remove_int(avl, 337); avl = remove_int(avl, 443); - avl = gpr_avl_add(avl, box(973), box(843)); + avl = gpr_avl_add(avl, box(973), box(843), NULL); avl = remove_int(avl, 930); avl = remove_int(avl, 242); - avl = gpr_avl_add(avl, box(997), box(846)); - avl = gpr_avl_add(avl, box(689), box(847)); + avl = gpr_avl_add(avl, box(997), box(846), NULL); + avl = gpr_avl_add(avl, box(689), box(847), NULL); avl = remove_int(avl, 318); - avl = gpr_avl_add(avl, box(703), box(849)); - avl = gpr_avl_add(avl, box(868), box(850)); - avl = gpr_avl_add(avl, box(200), box(851)); - avl = gpr_avl_add(avl, box(960), box(852)); - avl = gpr_avl_add(avl, box(80), box(853)); + avl = gpr_avl_add(avl, box(703), box(849), NULL); + avl = gpr_avl_add(avl, box(868), box(850), NULL); + avl = gpr_avl_add(avl, box(200), box(851), NULL); + avl = gpr_avl_add(avl, box(960), box(852), NULL); + avl = gpr_avl_add(avl, box(80), box(853), NULL); avl = remove_int(avl, 113); - avl = gpr_avl_add(avl, box(135), box(855)); + avl = gpr_avl_add(avl, box(135), box(855), NULL); avl = remove_int(avl, 529); - avl = gpr_avl_add(avl, box(366), box(857)); + avl = gpr_avl_add(avl, box(366), box(857), NULL); avl = remove_int(avl, 272); - avl = gpr_avl_add(avl, box(921), box(859)); + avl = gpr_avl_add(avl, box(921), box(859), NULL); avl = remove_int(avl, 497); - avl = gpr_avl_add(avl, box(712), box(861)); + avl = gpr_avl_add(avl, box(712), box(861), NULL); avl = remove_int(avl, 777); avl = remove_int(avl, 505); avl = remove_int(avl, 974); avl = remove_int(avl, 497); - avl = gpr_avl_add(avl, box(388), box(866)); - avl = gpr_avl_add(avl, box(29), box(867)); - avl = gpr_avl_add(avl, box(180), box(868)); - avl = gpr_avl_add(avl, box(983), box(869)); - avl = gpr_avl_add(avl, box(72), box(870)); - avl = gpr_avl_add(avl, box(693), box(871)); - avl = gpr_avl_add(avl, box(567), box(872)); + avl = gpr_avl_add(avl, box(388), box(866), NULL); + avl = gpr_avl_add(avl, box(29), box(867), NULL); + avl = gpr_avl_add(avl, box(180), box(868), NULL); + avl = gpr_avl_add(avl, box(983), box(869), NULL); + avl = gpr_avl_add(avl, box(72), box(870), NULL); + avl = gpr_avl_add(avl, box(693), box(871), NULL); + avl = gpr_avl_add(avl, box(567), box(872), NULL); avl = remove_int(avl, 549); avl = remove_int(avl, 351); - avl = gpr_avl_add(avl, box(1019), box(875)); + avl = gpr_avl_add(avl, box(1019), box(875), NULL); avl = remove_int(avl, 585); avl = remove_int(avl, 294); avl = remove_int(avl, 61); - avl = gpr_avl_add(avl, box(409), box(879)); - avl = gpr_avl_add(avl, box(984), box(880)); - avl = gpr_avl_add(avl, box(830), box(881)); + avl = gpr_avl_add(avl, box(409), box(879), NULL); + avl = gpr_avl_add(avl, box(984), box(880), NULL); + avl = gpr_avl_add(avl, box(830), box(881), NULL); avl = remove_int(avl, 579); - avl = gpr_avl_add(avl, box(672), box(883)); + avl = gpr_avl_add(avl, box(672), box(883), NULL); avl = remove_int(avl, 968); - gpr_avl_unref(avl); + gpr_avl_unref(avl, NULL); } static void test_badcase3(void) { @@ -1138,191 +1140,191 @@ static void test_badcase3(void) { avl = gpr_avl_create(&int_int_vtable); avl = remove_int(avl, 624); - avl = gpr_avl_add(avl, box(59), box(2)); - avl = gpr_avl_add(avl, box(494), box(3)); - avl = gpr_avl_add(avl, box(226), box(4)); + avl = gpr_avl_add(avl, box(59), box(2), NULL); + avl = gpr_avl_add(avl, box(494), box(3), NULL); + avl = gpr_avl_add(avl, box(226), box(4), NULL); avl = remove_int(avl, 524); - avl = gpr_avl_add(avl, box(540), box(6)); + avl = gpr_avl_add(avl, box(540), box(6), NULL); avl = remove_int(avl, 1008); - avl = gpr_avl_add(avl, box(502), box(8)); + avl = gpr_avl_add(avl, box(502), box(8), NULL); avl = remove_int(avl, 267); avl = remove_int(avl, 764); avl = remove_int(avl, 443); - avl = gpr_avl_add(avl, box(8), box(12)); + avl = gpr_avl_add(avl, box(8), box(12), NULL); avl = remove_int(avl, 291); avl = remove_int(avl, 796); avl = remove_int(avl, 1002); - avl = gpr_avl_add(avl, box(778), box(16)); + avl = gpr_avl_add(avl, box(778), box(16), NULL); avl = remove_int(avl, 621); avl = remove_int(avl, 891); avl = remove_int(avl, 880); - avl = gpr_avl_add(avl, box(197), box(20)); - avl = gpr_avl_add(avl, box(441), box(21)); - avl = gpr_avl_add(avl, box(719), box(22)); + avl = gpr_avl_add(avl, box(197), box(20), NULL); + avl = gpr_avl_add(avl, box(441), box(21), NULL); + avl = gpr_avl_add(avl, box(719), box(22), NULL); avl = remove_int(avl, 109); - avl = gpr_avl_add(avl, box(458), box(24)); + avl = gpr_avl_add(avl, box(458), box(24), NULL); avl = remove_int(avl, 86); - avl = gpr_avl_add(avl, box(897), box(26)); - avl = gpr_avl_add(avl, box(997), box(27)); + avl = gpr_avl_add(avl, box(897), box(26), NULL); + avl = gpr_avl_add(avl, box(997), box(27), NULL); avl = remove_int(avl, 235); avl = remove_int(avl, 425); avl = remove_int(avl, 186); - avl = gpr_avl_add(avl, box(887), box(31)); - avl = gpr_avl_add(avl, box(1005), box(32)); - avl = gpr_avl_add(avl, box(778), box(33)); - avl = gpr_avl_add(avl, box(575), box(34)); + avl = gpr_avl_add(avl, box(887), box(31), NULL); + avl = gpr_avl_add(avl, box(1005), box(32), NULL); + avl = gpr_avl_add(avl, box(778), box(33), NULL); + avl = gpr_avl_add(avl, box(575), box(34), NULL); avl = remove_int(avl, 966); avl = remove_int(avl, 1015); - avl = gpr_avl_add(avl, box(486), box(37)); - avl = gpr_avl_add(avl, box(809), box(38)); - avl = gpr_avl_add(avl, box(907), box(39)); - avl = gpr_avl_add(avl, box(971), box(40)); + avl = gpr_avl_add(avl, box(486), box(37), NULL); + avl = gpr_avl_add(avl, box(809), box(38), NULL); + avl = gpr_avl_add(avl, box(907), box(39), NULL); + avl = gpr_avl_add(avl, box(971), box(40), NULL); avl = remove_int(avl, 441); avl = remove_int(avl, 498); - avl = gpr_avl_add(avl, box(727), box(43)); + avl = gpr_avl_add(avl, box(727), box(43), NULL); avl = remove_int(avl, 679); avl = remove_int(avl, 740); avl = remove_int(avl, 532); - avl = gpr_avl_add(avl, box(805), box(47)); + avl = gpr_avl_add(avl, box(805), box(47), NULL); avl = remove_int(avl, 64); - avl = gpr_avl_add(avl, box(362), box(49)); - avl = gpr_avl_add(avl, box(170), box(50)); - avl = gpr_avl_add(avl, box(389), box(51)); - avl = gpr_avl_add(avl, box(689), box(52)); + avl = gpr_avl_add(avl, box(362), box(49), NULL); + avl = gpr_avl_add(avl, box(170), box(50), NULL); + avl = gpr_avl_add(avl, box(389), box(51), NULL); + avl = gpr_avl_add(avl, box(689), box(52), NULL); avl = remove_int(avl, 871); - avl = gpr_avl_add(avl, box(447), box(54)); + avl = gpr_avl_add(avl, box(447), box(54), NULL); avl = remove_int(avl, 718); - avl = gpr_avl_add(avl, box(724), box(56)); + avl = gpr_avl_add(avl, box(724), box(56), NULL); avl = remove_int(avl, 215); - avl = gpr_avl_add(avl, box(550), box(58)); + avl = gpr_avl_add(avl, box(550), box(58), NULL); avl = remove_int(avl, 932); - avl = gpr_avl_add(avl, box(47), box(60)); + avl = gpr_avl_add(avl, box(47), box(60), NULL); avl = remove_int(avl, 46); avl = remove_int(avl, 229); - avl = gpr_avl_add(avl, box(68), box(63)); - avl = gpr_avl_add(avl, box(387), box(64)); + avl = gpr_avl_add(avl, box(68), box(63), NULL); + avl = gpr_avl_add(avl, box(387), box(64), NULL); avl = remove_int(avl, 933); avl = remove_int(avl, 736); avl = remove_int(avl, 719); - avl = gpr_avl_add(avl, box(150), box(68)); + avl = gpr_avl_add(avl, box(150), box(68), NULL); avl = remove_int(avl, 875); avl = remove_int(avl, 298); - avl = gpr_avl_add(avl, box(991), box(71)); + avl = gpr_avl_add(avl, box(991), box(71), NULL); avl = remove_int(avl, 705); - avl = gpr_avl_add(avl, box(197), box(73)); - avl = gpr_avl_add(avl, box(101), box(74)); + avl = gpr_avl_add(avl, box(197), box(73), NULL); + avl = gpr_avl_add(avl, box(101), box(74), NULL); avl = remove_int(avl, 436); - avl = gpr_avl_add(avl, box(755), box(76)); - avl = gpr_avl_add(avl, box(727), box(77)); + avl = gpr_avl_add(avl, box(755), box(76), NULL); + avl = gpr_avl_add(avl, box(727), box(77), NULL); avl = remove_int(avl, 309); avl = remove_int(avl, 253); - avl = gpr_avl_add(avl, box(203), box(80)); + avl = gpr_avl_add(avl, box(203), box(80), NULL); avl = remove_int(avl, 231); - avl = gpr_avl_add(avl, box(461), box(82)); + avl = gpr_avl_add(avl, box(461), box(82), NULL); avl = remove_int(avl, 316); avl = remove_int(avl, 493); - avl = gpr_avl_add(avl, box(184), box(85)); + avl = gpr_avl_add(avl, box(184), box(85), NULL); avl = remove_int(avl, 737); - avl = gpr_avl_add(avl, box(790), box(87)); - avl = gpr_avl_add(avl, box(335), box(88)); + avl = gpr_avl_add(avl, box(790), box(87), NULL); + avl = gpr_avl_add(avl, box(335), box(88), NULL); avl = remove_int(avl, 649); - avl = gpr_avl_add(avl, box(69), box(90)); + avl = gpr_avl_add(avl, box(69), box(90), NULL); avl = remove_int(avl, 585); avl = remove_int(avl, 543); - avl = gpr_avl_add(avl, box(784), box(93)); - avl = gpr_avl_add(avl, box(60), box(94)); - avl = gpr_avl_add(avl, box(525), box(95)); - avl = gpr_avl_add(avl, box(177), box(96)); - avl = gpr_avl_add(avl, box(178), box(97)); - avl = gpr_avl_add(avl, box(683), box(98)); - avl = gpr_avl_add(avl, box(226), box(99)); - avl = gpr_avl_add(avl, box(662), box(100)); + avl = gpr_avl_add(avl, box(784), box(93), NULL); + avl = gpr_avl_add(avl, box(60), box(94), NULL); + avl = gpr_avl_add(avl, box(525), box(95), NULL); + avl = gpr_avl_add(avl, box(177), box(96), NULL); + avl = gpr_avl_add(avl, box(178), box(97), NULL); + avl = gpr_avl_add(avl, box(683), box(98), NULL); + avl = gpr_avl_add(avl, box(226), box(99), NULL); + avl = gpr_avl_add(avl, box(662), box(100), NULL); avl = remove_int(avl, 944); - avl = gpr_avl_add(avl, box(562), box(102)); - avl = gpr_avl_add(avl, box(793), box(103)); + avl = gpr_avl_add(avl, box(562), box(102), NULL); + avl = gpr_avl_add(avl, box(793), box(103), NULL); avl = remove_int(avl, 673); - avl = gpr_avl_add(avl, box(310), box(105)); + avl = gpr_avl_add(avl, box(310), box(105), NULL); avl = remove_int(avl, 479); avl = remove_int(avl, 543); avl = remove_int(avl, 159); avl = remove_int(avl, 850); - avl = gpr_avl_add(avl, box(318), box(110)); - avl = gpr_avl_add(avl, box(483), box(111)); - avl = gpr_avl_add(avl, box(84), box(112)); + avl = gpr_avl_add(avl, box(318), box(110), NULL); + avl = gpr_avl_add(avl, box(483), box(111), NULL); + avl = gpr_avl_add(avl, box(84), box(112), NULL); avl = remove_int(avl, 109); - avl = gpr_avl_add(avl, box(132), box(114)); - avl = gpr_avl_add(avl, box(920), box(115)); + avl = gpr_avl_add(avl, box(132), box(114), NULL); + avl = gpr_avl_add(avl, box(920), box(115), NULL); avl = remove_int(avl, 746); - avl = gpr_avl_add(avl, box(145), box(117)); - avl = gpr_avl_add(avl, box(526), box(118)); + avl = gpr_avl_add(avl, box(145), box(117), NULL); + avl = gpr_avl_add(avl, box(526), box(118), NULL); avl = remove_int(avl, 158); - avl = gpr_avl_add(avl, box(332), box(120)); - avl = gpr_avl_add(avl, box(918), box(121)); + avl = gpr_avl_add(avl, box(332), box(120), NULL); + avl = gpr_avl_add(avl, box(918), box(121), NULL); avl = remove_int(avl, 339); - avl = gpr_avl_add(avl, box(809), box(123)); - avl = gpr_avl_add(avl, box(742), box(124)); - avl = gpr_avl_add(avl, box(718), box(125)); + avl = gpr_avl_add(avl, box(809), box(123), NULL); + avl = gpr_avl_add(avl, box(742), box(124), NULL); + avl = gpr_avl_add(avl, box(718), box(125), NULL); avl = remove_int(avl, 988); avl = remove_int(avl, 531); avl = remove_int(avl, 840); - avl = gpr_avl_add(avl, box(816), box(129)); - avl = gpr_avl_add(avl, box(976), box(130)); + avl = gpr_avl_add(avl, box(816), box(129), NULL); + avl = gpr_avl_add(avl, box(976), box(130), NULL); avl = remove_int(avl, 743); avl = remove_int(avl, 528); avl = remove_int(avl, 982); - avl = gpr_avl_add(avl, box(803), box(134)); - avl = gpr_avl_add(avl, box(205), box(135)); - avl = gpr_avl_add(avl, box(584), box(136)); + avl = gpr_avl_add(avl, box(803), box(134), NULL); + avl = gpr_avl_add(avl, box(205), box(135), NULL); + avl = gpr_avl_add(avl, box(584), box(136), NULL); avl = remove_int(avl, 923); avl = remove_int(avl, 538); avl = remove_int(avl, 398); avl = remove_int(avl, 320); avl = remove_int(avl, 292); - avl = gpr_avl_add(avl, box(270), box(142)); - avl = gpr_avl_add(avl, box(333), box(143)); + avl = gpr_avl_add(avl, box(270), box(142), NULL); + avl = gpr_avl_add(avl, box(333), box(143), NULL); avl = remove_int(avl, 439); - avl = gpr_avl_add(avl, box(35), box(145)); - avl = gpr_avl_add(avl, box(837), box(146)); + avl = gpr_avl_add(avl, box(35), box(145), NULL); + avl = gpr_avl_add(avl, box(837), box(146), NULL); avl = remove_int(avl, 65); avl = remove_int(avl, 642); avl = remove_int(avl, 371); avl = remove_int(avl, 140); avl = remove_int(avl, 533); avl = remove_int(avl, 676); - avl = gpr_avl_add(avl, box(624), box(153)); - avl = gpr_avl_add(avl, box(116), box(154)); - avl = gpr_avl_add(avl, box(446), box(155)); + avl = gpr_avl_add(avl, box(624), box(153), NULL); + avl = gpr_avl_add(avl, box(116), box(154), NULL); + avl = gpr_avl_add(avl, box(446), box(155), NULL); avl = remove_int(avl, 91); avl = remove_int(avl, 721); avl = remove_int(avl, 537); - avl = gpr_avl_add(avl, box(448), box(159)); + avl = gpr_avl_add(avl, box(448), box(159), NULL); avl = remove_int(avl, 155); avl = remove_int(avl, 344); avl = remove_int(avl, 237); - avl = gpr_avl_add(avl, box(309), box(163)); - avl = gpr_avl_add(avl, box(434), box(164)); - avl = gpr_avl_add(avl, box(277), box(165)); + avl = gpr_avl_add(avl, box(309), box(163), NULL); + avl = gpr_avl_add(avl, box(434), box(164), NULL); + avl = gpr_avl_add(avl, box(277), box(165), NULL); avl = remove_int(avl, 233); - avl = gpr_avl_add(avl, box(275), box(167)); - avl = gpr_avl_add(avl, box(218), box(168)); - avl = gpr_avl_add(avl, box(76), box(169)); - avl = gpr_avl_add(avl, box(898), box(170)); + avl = gpr_avl_add(avl, box(275), box(167), NULL); + avl = gpr_avl_add(avl, box(218), box(168), NULL); + avl = gpr_avl_add(avl, box(76), box(169), NULL); + avl = gpr_avl_add(avl, box(898), box(170), NULL); avl = remove_int(avl, 771); - avl = gpr_avl_add(avl, box(237), box(172)); + avl = gpr_avl_add(avl, box(237), box(172), NULL); avl = remove_int(avl, 327); - avl = gpr_avl_add(avl, box(499), box(174)); + avl = gpr_avl_add(avl, box(499), box(174), NULL); avl = remove_int(avl, 727); avl = remove_int(avl, 234); avl = remove_int(avl, 623); avl = remove_int(avl, 458); avl = remove_int(avl, 326); avl = remove_int(avl, 589); - avl = gpr_avl_add(avl, box(442), box(181)); + avl = gpr_avl_add(avl, box(442), box(181), NULL); avl = remove_int(avl, 389); - avl = gpr_avl_add(avl, box(708), box(183)); - avl = gpr_avl_add(avl, box(594), box(184)); - avl = gpr_avl_add(avl, box(942), box(185)); - avl = gpr_avl_add(avl, box(282), box(186)); + avl = gpr_avl_add(avl, box(708), box(183), NULL); + avl = gpr_avl_add(avl, box(594), box(184), NULL); + avl = gpr_avl_add(avl, box(942), box(185), NULL); + avl = gpr_avl_add(avl, box(282), box(186), NULL); avl = remove_int(avl, 434); avl = remove_int(avl, 134); avl = remove_int(avl, 270); @@ -1332,125 +1334,125 @@ static void test_badcase3(void) { avl = remove_int(avl, 193); avl = remove_int(avl, 797); avl = remove_int(avl, 347); - avl = gpr_avl_add(avl, box(99), box(196)); - avl = gpr_avl_add(avl, box(161), box(197)); + avl = gpr_avl_add(avl, box(99), box(196), NULL); + avl = gpr_avl_add(avl, box(161), box(197), NULL); avl = remove_int(avl, 484); - avl = gpr_avl_add(avl, box(72), box(199)); + avl = gpr_avl_add(avl, box(72), box(199), NULL); avl = remove_int(avl, 629); - avl = gpr_avl_add(avl, box(522), box(201)); + avl = gpr_avl_add(avl, box(522), box(201), NULL); avl = remove_int(avl, 679); - avl = gpr_avl_add(avl, box(407), box(203)); + avl = gpr_avl_add(avl, box(407), box(203), NULL); avl = remove_int(avl, 693); - avl = gpr_avl_add(avl, box(424), box(205)); - avl = gpr_avl_add(avl, box(651), box(206)); - avl = gpr_avl_add(avl, box(927), box(207)); + avl = gpr_avl_add(avl, box(424), box(205), NULL); + avl = gpr_avl_add(avl, box(651), box(206), NULL); + avl = gpr_avl_add(avl, box(927), box(207), NULL); avl = remove_int(avl, 553); - avl = gpr_avl_add(avl, box(128), box(209)); - avl = gpr_avl_add(avl, box(616), box(210)); - avl = gpr_avl_add(avl, box(690), box(211)); + avl = gpr_avl_add(avl, box(128), box(209), NULL); + avl = gpr_avl_add(avl, box(616), box(210), NULL); + avl = gpr_avl_add(avl, box(690), box(211), NULL); avl = remove_int(avl, 241); avl = remove_int(avl, 179); - avl = gpr_avl_add(avl, box(697), box(214)); + avl = gpr_avl_add(avl, box(697), box(214), NULL); avl = remove_int(avl, 779); - avl = gpr_avl_add(avl, box(241), box(216)); + avl = gpr_avl_add(avl, box(241), box(216), NULL); avl = remove_int(avl, 190); avl = remove_int(avl, 210); - avl = gpr_avl_add(avl, box(711), box(219)); + avl = gpr_avl_add(avl, box(711), box(219), NULL); avl = remove_int(avl, 251); avl = remove_int(avl, 61); - avl = gpr_avl_add(avl, box(800), box(222)); + avl = gpr_avl_add(avl, box(800), box(222), NULL); avl = remove_int(avl, 551); - avl = gpr_avl_add(avl, box(61), box(224)); - avl = gpr_avl_add(avl, box(656), box(225)); + avl = gpr_avl_add(avl, box(61), box(224), NULL); + avl = gpr_avl_add(avl, box(656), box(225), NULL); avl = remove_int(avl, 130); avl = remove_int(avl, 368); avl = remove_int(avl, 150); avl = remove_int(avl, 73); - avl = gpr_avl_add(avl, box(799), box(230)); - avl = gpr_avl_add(avl, box(125), box(231)); + avl = gpr_avl_add(avl, box(799), box(230), NULL); + avl = gpr_avl_add(avl, box(125), box(231), NULL); avl = remove_int(avl, 107); - avl = gpr_avl_add(avl, box(938), box(233)); - avl = gpr_avl_add(avl, box(914), box(234)); - avl = gpr_avl_add(avl, box(197), box(235)); + avl = gpr_avl_add(avl, box(938), box(233), NULL); + avl = gpr_avl_add(avl, box(914), box(234), NULL); + avl = gpr_avl_add(avl, box(197), box(235), NULL); avl = remove_int(avl, 736); - avl = gpr_avl_add(avl, box(20), box(237)); + avl = gpr_avl_add(avl, box(20), box(237), NULL); avl = remove_int(avl, 224); avl = remove_int(avl, 841); - avl = gpr_avl_add(avl, box(226), box(240)); + avl = gpr_avl_add(avl, box(226), box(240), NULL); avl = remove_int(avl, 963); avl = remove_int(avl, 796); avl = remove_int(avl, 728); - avl = gpr_avl_add(avl, box(855), box(244)); - avl = gpr_avl_add(avl, box(769), box(245)); - avl = gpr_avl_add(avl, box(631), box(246)); + avl = gpr_avl_add(avl, box(855), box(244), NULL); + avl = gpr_avl_add(avl, box(769), box(245), NULL); + avl = gpr_avl_add(avl, box(631), box(246), NULL); avl = remove_int(avl, 648); - avl = gpr_avl_add(avl, box(187), box(248)); - avl = gpr_avl_add(avl, box(31), box(249)); + avl = gpr_avl_add(avl, box(187), box(248), NULL); + avl = gpr_avl_add(avl, box(31), box(249), NULL); avl = remove_int(avl, 163); - avl = gpr_avl_add(avl, box(218), box(251)); - avl = gpr_avl_add(avl, box(488), box(252)); - avl = gpr_avl_add(avl, box(387), box(253)); - avl = gpr_avl_add(avl, box(809), box(254)); - avl = gpr_avl_add(avl, box(997), box(255)); + avl = gpr_avl_add(avl, box(218), box(251), NULL); + avl = gpr_avl_add(avl, box(488), box(252), NULL); + avl = gpr_avl_add(avl, box(387), box(253), NULL); + avl = gpr_avl_add(avl, box(809), box(254), NULL); + avl = gpr_avl_add(avl, box(997), box(255), NULL); avl = remove_int(avl, 678); - avl = gpr_avl_add(avl, box(368), box(257)); - avl = gpr_avl_add(avl, box(220), box(258)); - avl = gpr_avl_add(avl, box(373), box(259)); + avl = gpr_avl_add(avl, box(368), box(257), NULL); + avl = gpr_avl_add(avl, box(220), box(258), NULL); + avl = gpr_avl_add(avl, box(373), box(259), NULL); avl = remove_int(avl, 874); avl = remove_int(avl, 682); avl = remove_int(avl, 1014); avl = remove_int(avl, 195); - avl = gpr_avl_add(avl, box(868), box(264)); + avl = gpr_avl_add(avl, box(868), box(264), NULL); avl = remove_int(avl, 254); avl = remove_int(avl, 456); - avl = gpr_avl_add(avl, box(906), box(267)); + avl = gpr_avl_add(avl, box(906), box(267), NULL); avl = remove_int(avl, 711); - avl = gpr_avl_add(avl, box(632), box(269)); + avl = gpr_avl_add(avl, box(632), box(269), NULL); avl = remove_int(avl, 474); - avl = gpr_avl_add(avl, box(508), box(271)); - avl = gpr_avl_add(avl, box(518), box(272)); + avl = gpr_avl_add(avl, box(508), box(271), NULL); + avl = gpr_avl_add(avl, box(518), box(272), NULL); avl = remove_int(avl, 579); avl = remove_int(avl, 948); - avl = gpr_avl_add(avl, box(789), box(275)); - avl = gpr_avl_add(avl, box(48), box(276)); - avl = gpr_avl_add(avl, box(256), box(277)); - avl = gpr_avl_add(avl, box(754), box(278)); + avl = gpr_avl_add(avl, box(789), box(275), NULL); + avl = gpr_avl_add(avl, box(48), box(276), NULL); + avl = gpr_avl_add(avl, box(256), box(277), NULL); + avl = gpr_avl_add(avl, box(754), box(278), NULL); avl = remove_int(avl, 215); - avl = gpr_avl_add(avl, box(679), box(280)); - avl = gpr_avl_add(avl, box(606), box(281)); + avl = gpr_avl_add(avl, box(679), box(280), NULL); + avl = gpr_avl_add(avl, box(606), box(281), NULL); avl = remove_int(avl, 941); avl = remove_int(avl, 31); - avl = gpr_avl_add(avl, box(758), box(284)); + avl = gpr_avl_add(avl, box(758), box(284), NULL); avl = remove_int(avl, 101); - avl = gpr_avl_add(avl, box(244), box(286)); - avl = gpr_avl_add(avl, box(337), box(287)); - avl = gpr_avl_add(avl, box(461), box(288)); + avl = gpr_avl_add(avl, box(244), box(286), NULL); + avl = gpr_avl_add(avl, box(337), box(287), NULL); + avl = gpr_avl_add(avl, box(461), box(288), NULL); avl = remove_int(avl, 476); - avl = gpr_avl_add(avl, box(845), box(290)); + avl = gpr_avl_add(avl, box(845), box(290), NULL); avl = remove_int(avl, 160); - avl = gpr_avl_add(avl, box(690), box(292)); + avl = gpr_avl_add(avl, box(690), box(292), NULL); avl = remove_int(avl, 931); - avl = gpr_avl_add(avl, box(869), box(294)); - avl = gpr_avl_add(avl, box(1019), box(295)); + avl = gpr_avl_add(avl, box(869), box(294), NULL); + avl = gpr_avl_add(avl, box(1019), box(295), NULL); avl = remove_int(avl, 591); avl = remove_int(avl, 635); avl = remove_int(avl, 67); - avl = gpr_avl_add(avl, box(113), box(299)); + avl = gpr_avl_add(avl, box(113), box(299), NULL); avl = remove_int(avl, 305); - avl = gpr_avl_add(avl, box(10), box(301)); + avl = gpr_avl_add(avl, box(10), box(301), NULL); avl = remove_int(avl, 823); avl = remove_int(avl, 288); avl = remove_int(avl, 239); - avl = gpr_avl_add(avl, box(646), box(305)); - avl = gpr_avl_add(avl, box(1006), box(306)); - avl = gpr_avl_add(avl, box(954), box(307)); - avl = gpr_avl_add(avl, box(199), box(308)); - avl = gpr_avl_add(avl, box(69), box(309)); - avl = gpr_avl_add(avl, box(984), box(310)); + avl = gpr_avl_add(avl, box(646), box(305), NULL); + avl = gpr_avl_add(avl, box(1006), box(306), NULL); + avl = gpr_avl_add(avl, box(954), box(307), NULL); + avl = gpr_avl_add(avl, box(199), box(308), NULL); + avl = gpr_avl_add(avl, box(69), box(309), NULL); + avl = gpr_avl_add(avl, box(984), box(310), NULL); avl = remove_int(avl, 568); avl = remove_int(avl, 666); avl = remove_int(avl, 37); - avl = gpr_avl_add(avl, box(845), box(314)); + avl = gpr_avl_add(avl, box(845), box(314), NULL); avl = remove_int(avl, 535); avl = remove_int(avl, 365); avl = remove_int(avl, 676); @@ -1458,372 +1460,372 @@ static void test_badcase3(void) { avl = remove_int(avl, 425); avl = remove_int(avl, 704); avl = remove_int(avl, 168); - avl = gpr_avl_add(avl, box(853), box(322)); - avl = gpr_avl_add(avl, box(335), box(323)); - avl = gpr_avl_add(avl, box(961), box(324)); - avl = gpr_avl_add(avl, box(73), box(325)); + avl = gpr_avl_add(avl, box(853), box(322), NULL); + avl = gpr_avl_add(avl, box(335), box(323), NULL); + avl = gpr_avl_add(avl, box(961), box(324), NULL); + avl = gpr_avl_add(avl, box(73), box(325), NULL); avl = remove_int(avl, 469); - avl = gpr_avl_add(avl, box(449), box(327)); + avl = gpr_avl_add(avl, box(449), box(327), NULL); avl = remove_int(avl, 821); - avl = gpr_avl_add(avl, box(845), box(329)); + avl = gpr_avl_add(avl, box(845), box(329), NULL); avl = remove_int(avl, 637); - avl = gpr_avl_add(avl, box(769), box(331)); - avl = gpr_avl_add(avl, box(901), box(332)); + avl = gpr_avl_add(avl, box(769), box(331), NULL); + avl = gpr_avl_add(avl, box(901), box(332), NULL); avl = remove_int(avl, 142); avl = remove_int(avl, 361); avl = remove_int(avl, 876); - avl = gpr_avl_add(avl, box(614), box(336)); - avl = gpr_avl_add(avl, box(729), box(337)); + avl = gpr_avl_add(avl, box(614), box(336), NULL); + avl = gpr_avl_add(avl, box(729), box(337), NULL); avl = remove_int(avl, 120); avl = remove_int(avl, 473); avl = remove_int(avl, 445); - avl = gpr_avl_add(avl, box(978), box(341)); - avl = gpr_avl_add(avl, box(164), box(342)); - avl = gpr_avl_add(avl, box(1), box(343)); + avl = gpr_avl_add(avl, box(978), box(341), NULL); + avl = gpr_avl_add(avl, box(164), box(342), NULL); + avl = gpr_avl_add(avl, box(1), box(343), NULL); avl = remove_int(avl, 890); - avl = gpr_avl_add(avl, box(605), box(345)); - avl = gpr_avl_add(avl, box(178), box(346)); - avl = gpr_avl_add(avl, box(481), box(347)); - avl = gpr_avl_add(avl, box(772), box(348)); + avl = gpr_avl_add(avl, box(605), box(345), NULL); + avl = gpr_avl_add(avl, box(178), box(346), NULL); + avl = gpr_avl_add(avl, box(481), box(347), NULL); + avl = gpr_avl_add(avl, box(772), box(348), NULL); avl = remove_int(avl, 824); avl = remove_int(avl, 167); avl = remove_int(avl, 151); - avl = gpr_avl_add(avl, box(698), box(352)); - avl = gpr_avl_add(avl, box(202), box(353)); - avl = gpr_avl_add(avl, box(921), box(354)); - avl = gpr_avl_add(avl, box(875), box(355)); + avl = gpr_avl_add(avl, box(698), box(352), NULL); + avl = gpr_avl_add(avl, box(202), box(353), NULL); + avl = gpr_avl_add(avl, box(921), box(354), NULL); + avl = gpr_avl_add(avl, box(875), box(355), NULL); avl = remove_int(avl, 197); avl = remove_int(avl, 232); - avl = gpr_avl_add(avl, box(209), box(358)); + avl = gpr_avl_add(avl, box(209), box(358), NULL); avl = remove_int(avl, 324); avl = remove_int(avl, 56); avl = remove_int(avl, 579); avl = remove_int(avl, 255); avl = remove_int(avl, 290); - avl = gpr_avl_add(avl, box(661), box(364)); - avl = gpr_avl_add(avl, box(113), box(365)); + avl = gpr_avl_add(avl, box(661), box(364), NULL); + avl = gpr_avl_add(avl, box(113), box(365), NULL); avl = remove_int(avl, 767); - avl = gpr_avl_add(avl, box(586), box(367)); - avl = gpr_avl_add(avl, box(121), box(368)); + avl = gpr_avl_add(avl, box(586), box(367), NULL); + avl = gpr_avl_add(avl, box(121), box(368), NULL); avl = remove_int(avl, 235); avl = remove_int(avl, 439); avl = remove_int(avl, 360); - avl = gpr_avl_add(avl, box(916), box(372)); + avl = gpr_avl_add(avl, box(916), box(372), NULL); avl = remove_int(avl, 999); - avl = gpr_avl_add(avl, box(825), box(374)); - avl = gpr_avl_add(avl, box(177), box(375)); + avl = gpr_avl_add(avl, box(825), box(374), NULL); + avl = gpr_avl_add(avl, box(177), box(375), NULL); avl = remove_int(avl, 204); avl = remove_int(avl, 92); - avl = gpr_avl_add(avl, box(794), box(378)); - avl = gpr_avl_add(avl, box(463), box(379)); - avl = gpr_avl_add(avl, box(472), box(380)); + avl = gpr_avl_add(avl, box(794), box(378), NULL); + avl = gpr_avl_add(avl, box(463), box(379), NULL); + avl = gpr_avl_add(avl, box(472), box(380), NULL); avl = remove_int(avl, 235); - avl = gpr_avl_add(avl, box(840), box(382)); + avl = gpr_avl_add(avl, box(840), box(382), NULL); avl = remove_int(avl, 657); - avl = gpr_avl_add(avl, box(586), box(384)); - avl = gpr_avl_add(avl, box(979), box(385)); + avl = gpr_avl_add(avl, box(586), box(384), NULL); + avl = gpr_avl_add(avl, box(979), box(385), NULL); avl = remove_int(avl, 979); - avl = gpr_avl_add(avl, box(639), box(387)); + avl = gpr_avl_add(avl, box(639), box(387), NULL); avl = remove_int(avl, 907); avl = remove_int(avl, 973); - avl = gpr_avl_add(avl, box(913), box(390)); - avl = gpr_avl_add(avl, box(566), box(391)); - avl = gpr_avl_add(avl, box(883), box(392)); - avl = gpr_avl_add(avl, box(552), box(393)); - avl = gpr_avl_add(avl, box(16), box(394)); + avl = gpr_avl_add(avl, box(913), box(390), NULL); + avl = gpr_avl_add(avl, box(566), box(391), NULL); + avl = gpr_avl_add(avl, box(883), box(392), NULL); + avl = gpr_avl_add(avl, box(552), box(393), NULL); + avl = gpr_avl_add(avl, box(16), box(394), NULL); avl = remove_int(avl, 60); - avl = gpr_avl_add(avl, box(567), box(396)); - avl = gpr_avl_add(avl, box(705), box(397)); - avl = gpr_avl_add(avl, box(94), box(398)); + avl = gpr_avl_add(avl, box(567), box(396), NULL); + avl = gpr_avl_add(avl, box(705), box(397), NULL); + avl = gpr_avl_add(avl, box(94), box(398), NULL); avl = remove_int(avl, 321); - avl = gpr_avl_add(avl, box(207), box(400)); - avl = gpr_avl_add(avl, box(682), box(401)); - avl = gpr_avl_add(avl, box(592), box(402)); - avl = gpr_avl_add(avl, box(10), box(403)); + avl = gpr_avl_add(avl, box(207), box(400), NULL); + avl = gpr_avl_add(avl, box(682), box(401), NULL); + avl = gpr_avl_add(avl, box(592), box(402), NULL); + avl = gpr_avl_add(avl, box(10), box(403), NULL); avl = remove_int(avl, 911); avl = remove_int(avl, 161); - avl = gpr_avl_add(avl, box(86), box(406)); + avl = gpr_avl_add(avl, box(86), box(406), NULL); avl = remove_int(avl, 893); avl = remove_int(avl, 362); - avl = gpr_avl_add(avl, box(599), box(409)); + avl = gpr_avl_add(avl, box(599), box(409), NULL); avl = remove_int(avl, 413); - avl = gpr_avl_add(avl, box(867), box(411)); + avl = gpr_avl_add(avl, box(867), box(411), NULL); avl = remove_int(avl, 955); - avl = gpr_avl_add(avl, box(341), box(413)); - avl = gpr_avl_add(avl, box(887), box(414)); + avl = gpr_avl_add(avl, box(341), box(413), NULL); + avl = gpr_avl_add(avl, box(887), box(414), NULL); avl = remove_int(avl, 706); - avl = gpr_avl_add(avl, box(939), box(416)); + avl = gpr_avl_add(avl, box(939), box(416), NULL); avl = remove_int(avl, 233); avl = remove_int(avl, 662); avl = remove_int(avl, 984); avl = remove_int(avl, 203); - avl = gpr_avl_add(avl, box(326), box(421)); + avl = gpr_avl_add(avl, box(326), box(421), NULL); avl = remove_int(avl, 848); - avl = gpr_avl_add(avl, box(235), box(423)); + avl = gpr_avl_add(avl, box(235), box(423), NULL); avl = remove_int(avl, 617); - avl = gpr_avl_add(avl, box(565), box(425)); + avl = gpr_avl_add(avl, box(565), box(425), NULL); avl = remove_int(avl, 469); - avl = gpr_avl_add(avl, box(988), box(427)); + avl = gpr_avl_add(avl, box(988), box(427), NULL); avl = remove_int(avl, 957); - avl = gpr_avl_add(avl, box(426), box(429)); + avl = gpr_avl_add(avl, box(426), box(429), NULL); avl = remove_int(avl, 967); - avl = gpr_avl_add(avl, box(890), box(431)); - avl = gpr_avl_add(avl, box(473), box(432)); + avl = gpr_avl_add(avl, box(890), box(431), NULL); + avl = gpr_avl_add(avl, box(473), box(432), NULL); avl = remove_int(avl, 367); avl = remove_int(avl, 344); avl = remove_int(avl, 660); avl = remove_int(avl, 448); avl = remove_int(avl, 837); avl = remove_int(avl, 158); - avl = gpr_avl_add(avl, box(459), box(439)); + avl = gpr_avl_add(avl, box(459), box(439), NULL); avl = remove_int(avl, 882); avl = remove_int(avl, 782); - avl = gpr_avl_add(avl, box(408), box(442)); - avl = gpr_avl_add(avl, box(728), box(443)); + avl = gpr_avl_add(avl, box(408), box(442), NULL); + avl = gpr_avl_add(avl, box(728), box(443), NULL); avl = remove_int(avl, 27); - avl = gpr_avl_add(avl, box(137), box(445)); - avl = gpr_avl_add(avl, box(239), box(446)); + avl = gpr_avl_add(avl, box(137), box(445), NULL); + avl = gpr_avl_add(avl, box(239), box(446), NULL); avl = remove_int(avl, 854); - avl = gpr_avl_add(avl, box(104), box(448)); - avl = gpr_avl_add(avl, box(823), box(449)); - avl = gpr_avl_add(avl, box(524), box(450)); - avl = gpr_avl_add(avl, box(995), box(451)); + avl = gpr_avl_add(avl, box(104), box(448), NULL); + avl = gpr_avl_add(avl, box(823), box(449), NULL); + avl = gpr_avl_add(avl, box(524), box(450), NULL); + avl = gpr_avl_add(avl, box(995), box(451), NULL); avl = remove_int(avl, 422); avl = remove_int(avl, 220); - avl = gpr_avl_add(avl, box(856), box(454)); + avl = gpr_avl_add(avl, box(856), box(454), NULL); avl = remove_int(avl, 332); - avl = gpr_avl_add(avl, box(679), box(456)); + avl = gpr_avl_add(avl, box(679), box(456), NULL); avl = remove_int(avl, 18); - avl = gpr_avl_add(avl, box(837), box(458)); + avl = gpr_avl_add(avl, box(837), box(458), NULL); avl = remove_int(avl, 405); avl = remove_int(avl, 877); avl = remove_int(avl, 835); - avl = gpr_avl_add(avl, box(547), box(462)); + avl = gpr_avl_add(avl, box(547), box(462), NULL); avl = remove_int(avl, 805); avl = remove_int(avl, 862); - avl = gpr_avl_add(avl, box(75), box(465)); + avl = gpr_avl_add(avl, box(75), box(465), NULL); avl = remove_int(avl, 41); - avl = gpr_avl_add(avl, box(310), box(467)); + avl = gpr_avl_add(avl, box(310), box(467), NULL); avl = remove_int(avl, 855); - avl = gpr_avl_add(avl, box(20), box(469)); + avl = gpr_avl_add(avl, box(20), box(469), NULL); avl = remove_int(avl, 186); avl = remove_int(avl, 378); avl = remove_int(avl, 442); avl = remove_int(avl, 930); - avl = gpr_avl_add(avl, box(118), box(474)); - avl = gpr_avl_add(avl, box(96), box(475)); + avl = gpr_avl_add(avl, box(118), box(474), NULL); + avl = gpr_avl_add(avl, box(96), box(475), NULL); avl = remove_int(avl, 854); - avl = gpr_avl_add(avl, box(65), box(477)); - avl = gpr_avl_add(avl, box(573), box(478)); - avl = gpr_avl_add(avl, box(4), box(479)); - avl = gpr_avl_add(avl, box(451), box(480)); - avl = gpr_avl_add(avl, box(774), box(481)); - avl = gpr_avl_add(avl, box(126), box(482)); + avl = gpr_avl_add(avl, box(65), box(477), NULL); + avl = gpr_avl_add(avl, box(573), box(478), NULL); + avl = gpr_avl_add(avl, box(4), box(479), NULL); + avl = gpr_avl_add(avl, box(451), box(480), NULL); + avl = gpr_avl_add(avl, box(774), box(481), NULL); + avl = gpr_avl_add(avl, box(126), box(482), NULL); avl = remove_int(avl, 956); avl = remove_int(avl, 591); avl = remove_int(avl, 644); - avl = gpr_avl_add(avl, box(304), box(486)); + avl = gpr_avl_add(avl, box(304), box(486), NULL); avl = remove_int(avl, 620); avl = remove_int(avl, 394); - avl = gpr_avl_add(avl, box(1002), box(489)); - avl = gpr_avl_add(avl, box(837), box(490)); + avl = gpr_avl_add(avl, box(1002), box(489), NULL); + avl = gpr_avl_add(avl, box(837), box(490), NULL); avl = remove_int(avl, 485); - avl = gpr_avl_add(avl, box(1005), box(492)); + avl = gpr_avl_add(avl, box(1005), box(492), NULL); avl = remove_int(avl, 21); - avl = gpr_avl_add(avl, box(396), box(494)); + avl = gpr_avl_add(avl, box(396), box(494), NULL); avl = remove_int(avl, 966); - avl = gpr_avl_add(avl, box(105), box(496)); - avl = gpr_avl_add(avl, box(316), box(497)); + avl = gpr_avl_add(avl, box(105), box(496), NULL); + avl = gpr_avl_add(avl, box(316), box(497), NULL); avl = remove_int(avl, 776); - avl = gpr_avl_add(avl, box(188), box(499)); + avl = gpr_avl_add(avl, box(188), box(499), NULL); avl = remove_int(avl, 200); - avl = gpr_avl_add(avl, box(98), box(501)); - avl = gpr_avl_add(avl, box(831), box(502)); - avl = gpr_avl_add(avl, box(227), box(503)); - avl = gpr_avl_add(avl, box(220), box(504)); + avl = gpr_avl_add(avl, box(98), box(501), NULL); + avl = gpr_avl_add(avl, box(831), box(502), NULL); + avl = gpr_avl_add(avl, box(227), box(503), NULL); + avl = gpr_avl_add(avl, box(220), box(504), NULL); avl = remove_int(avl, 715); avl = remove_int(avl, 279); - avl = gpr_avl_add(avl, box(701), box(507)); - avl = gpr_avl_add(avl, box(726), box(508)); - avl = gpr_avl_add(avl, box(815), box(509)); - avl = gpr_avl_add(avl, box(749), box(510)); + avl = gpr_avl_add(avl, box(701), box(507), NULL); + avl = gpr_avl_add(avl, box(726), box(508), NULL); + avl = gpr_avl_add(avl, box(815), box(509), NULL); + avl = gpr_avl_add(avl, box(749), box(510), NULL); avl = remove_int(avl, 946); avl = remove_int(avl, 449); avl = remove_int(avl, 62); avl = remove_int(avl, 487); - avl = gpr_avl_add(avl, box(545), box(515)); + avl = gpr_avl_add(avl, box(545), box(515), NULL); avl = remove_int(avl, 59); - avl = gpr_avl_add(avl, box(168), box(517)); + avl = gpr_avl_add(avl, box(168), box(517), NULL); avl = remove_int(avl, 337); - avl = gpr_avl_add(avl, box(69), box(519)); + avl = gpr_avl_add(avl, box(69), box(519), NULL); avl = remove_int(avl, 600); - avl = gpr_avl_add(avl, box(591), box(521)); - avl = gpr_avl_add(avl, box(960), box(522)); - avl = gpr_avl_add(avl, box(116), box(523)); + avl = gpr_avl_add(avl, box(591), box(521), NULL); + avl = gpr_avl_add(avl, box(960), box(522), NULL); + avl = gpr_avl_add(avl, box(116), box(523), NULL); avl = remove_int(avl, 991); - avl = gpr_avl_add(avl, box(760), box(525)); - avl = gpr_avl_add(avl, box(664), box(526)); - avl = gpr_avl_add(avl, box(547), box(527)); + avl = gpr_avl_add(avl, box(760), box(525), NULL); + avl = gpr_avl_add(avl, box(664), box(526), NULL); + avl = gpr_avl_add(avl, box(547), box(527), NULL); avl = remove_int(avl, 922); - avl = gpr_avl_add(avl, box(290), box(529)); - avl = gpr_avl_add(avl, box(859), box(530)); - avl = gpr_avl_add(avl, box(49), box(531)); + avl = gpr_avl_add(avl, box(290), box(529), NULL); + avl = gpr_avl_add(avl, box(859), box(530), NULL); + avl = gpr_avl_add(avl, box(49), box(531), NULL); avl = remove_int(avl, 455); avl = remove_int(avl, 786); - avl = gpr_avl_add(avl, box(613), box(534)); - avl = gpr_avl_add(avl, box(326), box(535)); + avl = gpr_avl_add(avl, box(613), box(534), NULL); + avl = gpr_avl_add(avl, box(326), box(535), NULL); avl = remove_int(avl, 615); - avl = gpr_avl_add(avl, box(45), box(537)); - avl = gpr_avl_add(avl, box(162), box(538)); - avl = gpr_avl_add(avl, box(189), box(539)); + avl = gpr_avl_add(avl, box(45), box(537), NULL); + avl = gpr_avl_add(avl, box(162), box(538), NULL); + avl = gpr_avl_add(avl, box(189), box(539), NULL); avl = remove_int(avl, 68); avl = remove_int(avl, 846); - avl = gpr_avl_add(avl, box(608), box(542)); + avl = gpr_avl_add(avl, box(608), box(542), NULL); avl = remove_int(avl, 821); - avl = gpr_avl_add(avl, box(978), box(544)); - avl = gpr_avl_add(avl, box(892), box(545)); + avl = gpr_avl_add(avl, box(978), box(544), NULL); + avl = gpr_avl_add(avl, box(892), box(545), NULL); avl = remove_int(avl, 924); - avl = gpr_avl_add(avl, box(708), box(547)); + avl = gpr_avl_add(avl, box(708), box(547), NULL); avl = remove_int(avl, 135); avl = remove_int(avl, 124); - avl = gpr_avl_add(avl, box(301), box(550)); - avl = gpr_avl_add(avl, box(939), box(551)); - avl = gpr_avl_add(avl, box(344), box(552)); + avl = gpr_avl_add(avl, box(301), box(550), NULL); + avl = gpr_avl_add(avl, box(939), box(551), NULL); + avl = gpr_avl_add(avl, box(344), box(552), NULL); avl = remove_int(avl, 443); avl = remove_int(avl, 122); - avl = gpr_avl_add(avl, box(636), box(555)); + avl = gpr_avl_add(avl, box(636), box(555), NULL); avl = remove_int(avl, 558); - avl = gpr_avl_add(avl, box(923), box(557)); + avl = gpr_avl_add(avl, box(923), box(557), NULL); avl = remove_int(avl, 827); - avl = gpr_avl_add(avl, box(649), box(559)); - avl = gpr_avl_add(avl, box(808), box(560)); + avl = gpr_avl_add(avl, box(649), box(559), NULL); + avl = gpr_avl_add(avl, box(808), box(560), NULL); avl = remove_int(avl, 570); avl = remove_int(avl, 434); - avl = gpr_avl_add(avl, box(40), box(563)); - avl = gpr_avl_add(avl, box(725), box(564)); + avl = gpr_avl_add(avl, box(40), box(563), NULL); + avl = gpr_avl_add(avl, box(725), box(564), NULL); avl = remove_int(avl, 295); avl = remove_int(avl, 615); avl = remove_int(avl, 919); avl = remove_int(avl, 170); avl = remove_int(avl, 442); avl = remove_int(avl, 971); - avl = gpr_avl_add(avl, box(483), box(571)); - avl = gpr_avl_add(avl, box(512), box(572)); + avl = gpr_avl_add(avl, box(483), box(571), NULL); + avl = gpr_avl_add(avl, box(512), box(572), NULL); avl = remove_int(avl, 648); avl = remove_int(avl, 78); avl = remove_int(avl, 72); avl = remove_int(avl, 790); avl = remove_int(avl, 571); - avl = gpr_avl_add(avl, box(898), box(578)); + avl = gpr_avl_add(avl, box(898), box(578), NULL); avl = remove_int(avl, 770); avl = remove_int(avl, 776); - avl = gpr_avl_add(avl, box(602), box(581)); + avl = gpr_avl_add(avl, box(602), box(581), NULL); avl = remove_int(avl, 251); - avl = gpr_avl_add(avl, box(303), box(583)); + avl = gpr_avl_add(avl, box(303), box(583), NULL); avl = remove_int(avl, 837); - avl = gpr_avl_add(avl, box(714), box(585)); + avl = gpr_avl_add(avl, box(714), box(585), NULL); avl = remove_int(avl, 800); - avl = gpr_avl_add(avl, box(266), box(587)); - avl = gpr_avl_add(avl, box(555), box(588)); + avl = gpr_avl_add(avl, box(266), box(587), NULL); + avl = gpr_avl_add(avl, box(555), box(588), NULL); avl = remove_int(avl, 604); avl = remove_int(avl, 163); avl = remove_int(avl, 497); - avl = gpr_avl_add(avl, box(296), box(592)); + avl = gpr_avl_add(avl, box(296), box(592), NULL); avl = remove_int(avl, 129); - avl = gpr_avl_add(avl, box(656), box(594)); + avl = gpr_avl_add(avl, box(656), box(594), NULL); avl = remove_int(avl, 769); avl = remove_int(avl, 941); - avl = gpr_avl_add(avl, box(775), box(597)); - avl = gpr_avl_add(avl, box(846), box(598)); + avl = gpr_avl_add(avl, box(775), box(597), NULL); + avl = gpr_avl_add(avl, box(846), box(598), NULL); avl = remove_int(avl, 591); avl = remove_int(avl, 801); avl = remove_int(avl, 419); avl = remove_int(avl, 455); - avl = gpr_avl_add(avl, box(866), box(603)); - avl = gpr_avl_add(avl, box(575), box(604)); - avl = gpr_avl_add(avl, box(620), box(605)); + avl = gpr_avl_add(avl, box(866), box(603), NULL); + avl = gpr_avl_add(avl, box(575), box(604), NULL); + avl = gpr_avl_add(avl, box(620), box(605), NULL); avl = remove_int(avl, 100); avl = remove_int(avl, 667); - avl = gpr_avl_add(avl, box(138), box(608)); - avl = gpr_avl_add(avl, box(566), box(609)); - avl = gpr_avl_add(avl, box(673), box(610)); - avl = gpr_avl_add(avl, box(178), box(611)); + avl = gpr_avl_add(avl, box(138), box(608), NULL); + avl = gpr_avl_add(avl, box(566), box(609), NULL); + avl = gpr_avl_add(avl, box(673), box(610), NULL); + avl = gpr_avl_add(avl, box(178), box(611), NULL); avl = remove_int(avl, 659); - avl = gpr_avl_add(avl, box(759), box(613)); - avl = gpr_avl_add(avl, box(1008), box(614)); + avl = gpr_avl_add(avl, box(759), box(613), NULL); + avl = gpr_avl_add(avl, box(1008), box(614), NULL); avl = remove_int(avl, 116); - avl = gpr_avl_add(avl, box(608), box(616)); - avl = gpr_avl_add(avl, box(339), box(617)); - avl = gpr_avl_add(avl, box(197), box(618)); + avl = gpr_avl_add(avl, box(608), box(616), NULL); + avl = gpr_avl_add(avl, box(339), box(617), NULL); + avl = gpr_avl_add(avl, box(197), box(618), NULL); avl = remove_int(avl, 25); avl = remove_int(avl, 628); - avl = gpr_avl_add(avl, box(487), box(621)); + avl = gpr_avl_add(avl, box(487), box(621), NULL); avl = remove_int(avl, 739); avl = remove_int(avl, 100); avl = remove_int(avl, 928); - avl = gpr_avl_add(avl, box(647), box(625)); + avl = gpr_avl_add(avl, box(647), box(625), NULL); avl = remove_int(avl, 978); avl = remove_int(avl, 143); avl = remove_int(avl, 755); - avl = gpr_avl_add(avl, box(71), box(629)); + avl = gpr_avl_add(avl, box(71), box(629), NULL); avl = remove_int(avl, 205); - avl = gpr_avl_add(avl, box(501), box(631)); + avl = gpr_avl_add(avl, box(501), box(631), NULL); avl = remove_int(avl, 723); avl = remove_int(avl, 852); avl = remove_int(avl, 1021); avl = remove_int(avl, 670); avl = remove_int(avl, 500); - avl = gpr_avl_add(avl, box(330), box(637)); + avl = gpr_avl_add(avl, box(330), box(637), NULL); avl = remove_int(avl, 264); - avl = gpr_avl_add(avl, box(69), box(639)); + avl = gpr_avl_add(avl, box(69), box(639), NULL); avl = remove_int(avl, 73); - avl = gpr_avl_add(avl, box(745), box(641)); + avl = gpr_avl_add(avl, box(745), box(641), NULL); avl = remove_int(avl, 518); avl = remove_int(avl, 641); avl = remove_int(avl, 768); - avl = gpr_avl_add(avl, box(988), box(645)); - avl = gpr_avl_add(avl, box(899), box(646)); + avl = gpr_avl_add(avl, box(988), box(645), NULL); + avl = gpr_avl_add(avl, box(899), box(646), NULL); avl = remove_int(avl, 763); avl = remove_int(avl, 281); avl = remove_int(avl, 496); - avl = gpr_avl_add(avl, box(445), box(650)); + avl = gpr_avl_add(avl, box(445), box(650), NULL); avl = remove_int(avl, 905); - avl = gpr_avl_add(avl, box(275), box(652)); - avl = gpr_avl_add(avl, box(137), box(653)); + avl = gpr_avl_add(avl, box(275), box(652), NULL); + avl = gpr_avl_add(avl, box(137), box(653), NULL); avl = remove_int(avl, 642); - avl = gpr_avl_add(avl, box(708), box(655)); + avl = gpr_avl_add(avl, box(708), box(655), NULL); avl = remove_int(avl, 922); - avl = gpr_avl_add(avl, box(743), box(657)); + avl = gpr_avl_add(avl, box(743), box(657), NULL); avl = remove_int(avl, 295); avl = remove_int(avl, 665); avl = remove_int(avl, 48); - avl = gpr_avl_add(avl, box(1012), box(661)); + avl = gpr_avl_add(avl, box(1012), box(661), NULL); avl = remove_int(avl, 71); avl = remove_int(avl, 523); - avl = gpr_avl_add(avl, box(319), box(664)); + avl = gpr_avl_add(avl, box(319), box(664), NULL); avl = remove_int(avl, 632); - avl = gpr_avl_add(avl, box(137), box(666)); - avl = gpr_avl_add(avl, box(686), box(667)); - avl = gpr_avl_add(avl, box(724), box(668)); - avl = gpr_avl_add(avl, box(952), box(669)); - avl = gpr_avl_add(avl, box(5), box(670)); + avl = gpr_avl_add(avl, box(137), box(666), NULL); + avl = gpr_avl_add(avl, box(686), box(667), NULL); + avl = gpr_avl_add(avl, box(724), box(668), NULL); + avl = gpr_avl_add(avl, box(952), box(669), NULL); + avl = gpr_avl_add(avl, box(5), box(670), NULL); avl = remove_int(avl, 35); - avl = gpr_avl_add(avl, box(43), box(672)); - avl = gpr_avl_add(avl, box(320), box(673)); - avl = gpr_avl_add(avl, box(115), box(674)); + avl = gpr_avl_add(avl, box(43), box(672), NULL); + avl = gpr_avl_add(avl, box(320), box(673), NULL); + avl = gpr_avl_add(avl, box(115), box(674), NULL); avl = remove_int(avl, 377); avl = remove_int(avl, 591); avl = remove_int(avl, 87); avl = remove_int(avl, 93); - avl = gpr_avl_add(avl, box(1016), box(679)); - avl = gpr_avl_add(avl, box(605), box(680)); - avl = gpr_avl_add(avl, box(152), box(681)); - avl = gpr_avl_add(avl, box(113), box(682)); + avl = gpr_avl_add(avl, box(1016), box(679), NULL); + avl = gpr_avl_add(avl, box(605), box(680), NULL); + avl = gpr_avl_add(avl, box(152), box(681), NULL); + avl = gpr_avl_add(avl, box(113), box(682), NULL); avl = remove_int(avl, 131); avl = remove_int(avl, 637); - avl = gpr_avl_add(avl, box(156), box(685)); + avl = gpr_avl_add(avl, box(156), box(685), NULL); avl = remove_int(avl, 696); - avl = gpr_avl_add(avl, box(546), box(687)); + avl = gpr_avl_add(avl, box(546), box(687), NULL); avl = remove_int(avl, 970); avl = remove_int(avl, 53); avl = remove_int(avl, 827); @@ -1837,22 +1839,22 @@ static void test_badcase3(void) { avl = remove_int(avl, 244); avl = remove_int(avl, 576); avl = remove_int(avl, 413); - avl = gpr_avl_add(avl, box(500), box(701)); + avl = gpr_avl_add(avl, box(500), box(701), NULL); avl = remove_int(avl, 924); - avl = gpr_avl_add(avl, box(825), box(703)); + avl = gpr_avl_add(avl, box(825), box(703), NULL); avl = remove_int(avl, 888); avl = remove_int(avl, 931); - avl = gpr_avl_add(avl, box(285), box(706)); + avl = gpr_avl_add(avl, box(285), box(706), NULL); avl = remove_int(avl, 62); avl = remove_int(avl, 444); avl = remove_int(avl, 946); - avl = gpr_avl_add(avl, box(122), box(710)); - avl = gpr_avl_add(avl, box(846), box(711)); + avl = gpr_avl_add(avl, box(122), box(710), NULL); + avl = gpr_avl_add(avl, box(846), box(711), NULL); avl = remove_int(avl, 628); - avl = gpr_avl_add(avl, box(511), box(713)); - avl = gpr_avl_add(avl, box(398), box(714)); + avl = gpr_avl_add(avl, box(511), box(713), NULL); + avl = gpr_avl_add(avl, box(398), box(714), NULL); avl = remove_int(avl, 730); - avl = gpr_avl_add(avl, box(797), box(716)); + avl = gpr_avl_add(avl, box(797), box(716), NULL); avl = remove_int(avl, 897); avl = remove_int(avl, 228); avl = remove_int(avl, 544); @@ -1861,51 +1863,51 @@ static void test_badcase3(void) { avl = remove_int(avl, 583); avl = remove_int(avl, 894); avl = remove_int(avl, 942); - avl = gpr_avl_add(avl, box(346), box(725)); - avl = gpr_avl_add(avl, box(1015), box(726)); + avl = gpr_avl_add(avl, box(346), box(725), NULL); + avl = gpr_avl_add(avl, box(1015), box(726), NULL); avl = remove_int(avl, 813); - avl = gpr_avl_add(avl, box(213), box(728)); + avl = gpr_avl_add(avl, box(213), box(728), NULL); avl = remove_int(avl, 468); avl = remove_int(avl, 365); avl = remove_int(avl, 399); - avl = gpr_avl_add(avl, box(380), box(732)); + avl = gpr_avl_add(avl, box(380), box(732), NULL); avl = remove_int(avl, 835); avl = remove_int(avl, 970); - avl = gpr_avl_add(avl, box(700), box(735)); - avl = gpr_avl_add(avl, box(807), box(736)); + avl = gpr_avl_add(avl, box(700), box(735), NULL); + avl = gpr_avl_add(avl, box(807), box(736), NULL); avl = remove_int(avl, 312); avl = remove_int(avl, 282); avl = remove_int(avl, 370); avl = remove_int(avl, 999); avl = remove_int(avl, 241); avl = remove_int(avl, 884); - avl = gpr_avl_add(avl, box(587), box(743)); - avl = gpr_avl_add(avl, box(332), box(744)); + avl = gpr_avl_add(avl, box(587), box(743), NULL); + avl = gpr_avl_add(avl, box(332), box(744), NULL); avl = remove_int(avl, 686); avl = remove_int(avl, 206); avl = remove_int(avl, 835); - avl = gpr_avl_add(avl, box(334), box(748)); + avl = gpr_avl_add(avl, box(334), box(748), NULL); avl = remove_int(avl, 171); - avl = gpr_avl_add(avl, box(1002), box(750)); - avl = gpr_avl_add(avl, box(779), box(751)); - avl = gpr_avl_add(avl, box(307), box(752)); - avl = gpr_avl_add(avl, box(127), box(753)); - avl = gpr_avl_add(avl, box(251), box(754)); + avl = gpr_avl_add(avl, box(1002), box(750), NULL); + avl = gpr_avl_add(avl, box(779), box(751), NULL); + avl = gpr_avl_add(avl, box(307), box(752), NULL); + avl = gpr_avl_add(avl, box(127), box(753), NULL); + avl = gpr_avl_add(avl, box(251), box(754), NULL); avl = remove_int(avl, 790); avl = remove_int(avl, 189); avl = remove_int(avl, 193); avl = remove_int(avl, 38); avl = remove_int(avl, 124); - avl = gpr_avl_add(avl, box(812), box(760)); + avl = gpr_avl_add(avl, box(812), box(760), NULL); avl = remove_int(avl, 43); - avl = gpr_avl_add(avl, box(871), box(762)); - avl = gpr_avl_add(avl, box(580), box(763)); + avl = gpr_avl_add(avl, box(871), box(762), NULL); + avl = gpr_avl_add(avl, box(580), box(763), NULL); avl = remove_int(avl, 501); avl = remove_int(avl, 462); avl = remove_int(avl, 599); - avl = gpr_avl_add(avl, box(240), box(767)); - avl = gpr_avl_add(avl, box(285), box(768)); - avl = gpr_avl_add(avl, box(472), box(769)); + avl = gpr_avl_add(avl, box(240), box(767), NULL); + avl = gpr_avl_add(avl, box(285), box(768), NULL); + avl = gpr_avl_add(avl, box(472), box(769), NULL); avl = remove_int(avl, 865); avl = remove_int(avl, 763); avl = remove_int(avl, 245); @@ -1913,48 +1915,48 @@ static void test_badcase3(void) { avl = remove_int(avl, 713); avl = remove_int(avl, 654); avl = remove_int(avl, 1014); - avl = gpr_avl_add(avl, box(495), box(777)); - avl = gpr_avl_add(avl, box(552), box(778)); + avl = gpr_avl_add(avl, box(495), box(777), NULL); + avl = gpr_avl_add(avl, box(552), box(778), NULL); avl = remove_int(avl, 19); avl = remove_int(avl, 803); - avl = gpr_avl_add(avl, box(508), box(781)); + avl = gpr_avl_add(avl, box(508), box(781), NULL); avl = remove_int(avl, 699); avl = remove_int(avl, 260); avl = remove_int(avl, 92); avl = remove_int(avl, 497); - avl = gpr_avl_add(avl, box(970), box(786)); + avl = gpr_avl_add(avl, box(970), box(786), NULL); avl = remove_int(avl, 987); avl = remove_int(avl, 168); avl = remove_int(avl, 476); avl = remove_int(avl, 248); - avl = gpr_avl_add(avl, box(358), box(791)); + avl = gpr_avl_add(avl, box(358), box(791), NULL); avl = remove_int(avl, 804); avl = remove_int(avl, 77); avl = remove_int(avl, 905); avl = remove_int(avl, 362); - avl = gpr_avl_add(avl, box(578), box(796)); + avl = gpr_avl_add(avl, box(578), box(796), NULL); avl = remove_int(avl, 38); avl = remove_int(avl, 595); - avl = gpr_avl_add(avl, box(213), box(799)); + avl = gpr_avl_add(avl, box(213), box(799), NULL); avl = remove_int(avl, 7); avl = remove_int(avl, 620); - avl = gpr_avl_add(avl, box(946), box(802)); + avl = gpr_avl_add(avl, box(946), box(802), NULL); avl = remove_int(avl, 145); - avl = gpr_avl_add(avl, box(628), box(804)); + avl = gpr_avl_add(avl, box(628), box(804), NULL); avl = remove_int(avl, 972); - avl = gpr_avl_add(avl, box(728), box(806)); + avl = gpr_avl_add(avl, box(728), box(806), NULL); avl = remove_int(avl, 91); - avl = gpr_avl_add(avl, box(136), box(808)); - avl = gpr_avl_add(avl, box(841), box(809)); - avl = gpr_avl_add(avl, box(265), box(810)); - avl = gpr_avl_add(avl, box(701), box(811)); - avl = gpr_avl_add(avl, box(27), box(812)); + avl = gpr_avl_add(avl, box(136), box(808), NULL); + avl = gpr_avl_add(avl, box(841), box(809), NULL); + avl = gpr_avl_add(avl, box(265), box(810), NULL); + avl = gpr_avl_add(avl, box(701), box(811), NULL); + avl = gpr_avl_add(avl, box(27), box(812), NULL); avl = remove_int(avl, 72); avl = remove_int(avl, 14); - avl = gpr_avl_add(avl, box(286), box(815)); + avl = gpr_avl_add(avl, box(286), box(815), NULL); avl = remove_int(avl, 996); avl = remove_int(avl, 998); - avl = gpr_avl_add(avl, box(466), box(818)); + avl = gpr_avl_add(avl, box(466), box(818), NULL); avl = remove_int(avl, 1009); avl = remove_int(avl, 741); avl = remove_int(avl, 947); @@ -1963,138 +1965,138 @@ static void test_badcase3(void) { avl = remove_int(avl, 183); avl = remove_int(avl, 395); avl = remove_int(avl, 951); - avl = gpr_avl_add(avl, box(267), box(827)); + avl = gpr_avl_add(avl, box(267), box(827), NULL); avl = remove_int(avl, 812); - avl = gpr_avl_add(avl, box(577), box(829)); + avl = gpr_avl_add(avl, box(577), box(829), NULL); avl = remove_int(avl, 624); avl = remove_int(avl, 847); avl = remove_int(avl, 745); - avl = gpr_avl_add(avl, box(491), box(833)); - avl = gpr_avl_add(avl, box(941), box(834)); + avl = gpr_avl_add(avl, box(491), box(833), NULL); + avl = gpr_avl_add(avl, box(941), box(834), NULL); avl = remove_int(avl, 258); - avl = gpr_avl_add(avl, box(410), box(836)); - avl = gpr_avl_add(avl, box(80), box(837)); - avl = gpr_avl_add(avl, box(196), box(838)); - avl = gpr_avl_add(avl, box(5), box(839)); + avl = gpr_avl_add(avl, box(410), box(836), NULL); + avl = gpr_avl_add(avl, box(80), box(837), NULL); + avl = gpr_avl_add(avl, box(196), box(838), NULL); + avl = gpr_avl_add(avl, box(5), box(839), NULL); avl = remove_int(avl, 782); - avl = gpr_avl_add(avl, box(827), box(841)); + avl = gpr_avl_add(avl, box(827), box(841), NULL); avl = remove_int(avl, 472); avl = remove_int(avl, 664); - avl = gpr_avl_add(avl, box(409), box(844)); - avl = gpr_avl_add(avl, box(62), box(845)); + avl = gpr_avl_add(avl, box(409), box(844), NULL); + avl = gpr_avl_add(avl, box(62), box(845), NULL); avl = remove_int(avl, 56); avl = remove_int(avl, 606); avl = remove_int(avl, 707); avl = remove_int(avl, 989); avl = remove_int(avl, 549); avl = remove_int(avl, 259); - avl = gpr_avl_add(avl, box(405), box(852)); + avl = gpr_avl_add(avl, box(405), box(852), NULL); avl = remove_int(avl, 587); avl = remove_int(avl, 350); - avl = gpr_avl_add(avl, box(980), box(855)); - avl = gpr_avl_add(avl, box(992), box(856)); - avl = gpr_avl_add(avl, box(818), box(857)); + avl = gpr_avl_add(avl, box(980), box(855), NULL); + avl = gpr_avl_add(avl, box(992), box(856), NULL); + avl = gpr_avl_add(avl, box(818), box(857), NULL); avl = remove_int(avl, 853); avl = remove_int(avl, 701); - avl = gpr_avl_add(avl, box(675), box(860)); + avl = gpr_avl_add(avl, box(675), box(860), NULL); avl = remove_int(avl, 248); avl = remove_int(avl, 649); - avl = gpr_avl_add(avl, box(508), box(863)); + avl = gpr_avl_add(avl, box(508), box(863), NULL); avl = remove_int(avl, 927); - avl = gpr_avl_add(avl, box(957), box(865)); - avl = gpr_avl_add(avl, box(698), box(866)); - avl = gpr_avl_add(avl, box(388), box(867)); - avl = gpr_avl_add(avl, box(532), box(868)); - avl = gpr_avl_add(avl, box(681), box(869)); + avl = gpr_avl_add(avl, box(957), box(865), NULL); + avl = gpr_avl_add(avl, box(698), box(866), NULL); + avl = gpr_avl_add(avl, box(388), box(867), NULL); + avl = gpr_avl_add(avl, box(532), box(868), NULL); + avl = gpr_avl_add(avl, box(681), box(869), NULL); avl = remove_int(avl, 544); avl = remove_int(avl, 991); avl = remove_int(avl, 397); - avl = gpr_avl_add(avl, box(954), box(873)); - avl = gpr_avl_add(avl, box(219), box(874)); - avl = gpr_avl_add(avl, box(465), box(875)); + avl = gpr_avl_add(avl, box(954), box(873), NULL); + avl = gpr_avl_add(avl, box(219), box(874), NULL); + avl = gpr_avl_add(avl, box(465), box(875), NULL); avl = remove_int(avl, 371); - avl = gpr_avl_add(avl, box(601), box(877)); - avl = gpr_avl_add(avl, box(543), box(878)); + avl = gpr_avl_add(avl, box(601), box(877), NULL); + avl = gpr_avl_add(avl, box(543), box(878), NULL); avl = remove_int(avl, 329); - avl = gpr_avl_add(avl, box(560), box(880)); + avl = gpr_avl_add(avl, box(560), box(880), NULL); avl = remove_int(avl, 898); - avl = gpr_avl_add(avl, box(455), box(882)); + avl = gpr_avl_add(avl, box(455), box(882), NULL); avl = remove_int(avl, 313); - avl = gpr_avl_add(avl, box(215), box(884)); + avl = gpr_avl_add(avl, box(215), box(884), NULL); avl = remove_int(avl, 846); - avl = gpr_avl_add(avl, box(608), box(886)); + avl = gpr_avl_add(avl, box(608), box(886), NULL); avl = remove_int(avl, 248); - avl = gpr_avl_add(avl, box(575), box(888)); + avl = gpr_avl_add(avl, box(575), box(888), NULL); avl = remove_int(avl, 207); avl = remove_int(avl, 810); avl = remove_int(avl, 665); avl = remove_int(avl, 361); - avl = gpr_avl_add(avl, box(154), box(893)); - avl = gpr_avl_add(avl, box(329), box(894)); - avl = gpr_avl_add(avl, box(326), box(895)); + avl = gpr_avl_add(avl, box(154), box(893), NULL); + avl = gpr_avl_add(avl, box(329), box(894), NULL); + avl = gpr_avl_add(avl, box(326), box(895), NULL); avl = remove_int(avl, 746); avl = remove_int(avl, 99); - avl = gpr_avl_add(avl, box(464), box(898)); - avl = gpr_avl_add(avl, box(141), box(899)); + avl = gpr_avl_add(avl, box(464), box(898), NULL); + avl = gpr_avl_add(avl, box(141), box(899), NULL); avl = remove_int(avl, 383); - avl = gpr_avl_add(avl, box(414), box(901)); - avl = gpr_avl_add(avl, box(777), box(902)); + avl = gpr_avl_add(avl, box(414), box(901), NULL); + avl = gpr_avl_add(avl, box(777), box(902), NULL); avl = remove_int(avl, 972); avl = remove_int(avl, 841); avl = remove_int(avl, 100); - avl = gpr_avl_add(avl, box(828), box(906)); + avl = gpr_avl_add(avl, box(828), box(906), NULL); avl = remove_int(avl, 785); - avl = gpr_avl_add(avl, box(1008), box(908)); - avl = gpr_avl_add(avl, box(46), box(909)); + avl = gpr_avl_add(avl, box(1008), box(908), NULL); + avl = gpr_avl_add(avl, box(46), box(909), NULL); avl = remove_int(avl, 399); - avl = gpr_avl_add(avl, box(178), box(911)); - avl = gpr_avl_add(avl, box(573), box(912)); + avl = gpr_avl_add(avl, box(178), box(911), NULL); + avl = gpr_avl_add(avl, box(573), box(912), NULL); avl = remove_int(avl, 299); - avl = gpr_avl_add(avl, box(690), box(914)); - avl = gpr_avl_add(avl, box(692), box(915)); + avl = gpr_avl_add(avl, box(690), box(914), NULL); + avl = gpr_avl_add(avl, box(692), box(915), NULL); avl = remove_int(avl, 404); avl = remove_int(avl, 16); avl = remove_int(avl, 746); avl = remove_int(avl, 486); avl = remove_int(avl, 119); - avl = gpr_avl_add(avl, box(167), box(921)); + avl = gpr_avl_add(avl, box(167), box(921), NULL); avl = remove_int(avl, 328); - avl = gpr_avl_add(avl, box(89), box(923)); + avl = gpr_avl_add(avl, box(89), box(923), NULL); avl = remove_int(avl, 867); avl = remove_int(avl, 626); avl = remove_int(avl, 507); - avl = gpr_avl_add(avl, box(365), box(927)); - avl = gpr_avl_add(avl, box(58), box(928)); - avl = gpr_avl_add(avl, box(70), box(929)); + avl = gpr_avl_add(avl, box(365), box(927), NULL); + avl = gpr_avl_add(avl, box(58), box(928), NULL); + avl = gpr_avl_add(avl, box(70), box(929), NULL); avl = remove_int(avl, 81); avl = remove_int(avl, 797); - avl = gpr_avl_add(avl, box(846), box(932)); + avl = gpr_avl_add(avl, box(846), box(932), NULL); avl = remove_int(avl, 642); - avl = gpr_avl_add(avl, box(777), box(934)); + avl = gpr_avl_add(avl, box(777), box(934), NULL); avl = remove_int(avl, 107); - avl = gpr_avl_add(avl, box(691), box(936)); - avl = gpr_avl_add(avl, box(820), box(937)); - avl = gpr_avl_add(avl, box(202), box(938)); - avl = gpr_avl_add(avl, box(308), box(939)); - avl = gpr_avl_add(avl, box(20), box(940)); + avl = gpr_avl_add(avl, box(691), box(936), NULL); + avl = gpr_avl_add(avl, box(820), box(937), NULL); + avl = gpr_avl_add(avl, box(202), box(938), NULL); + avl = gpr_avl_add(avl, box(308), box(939), NULL); + avl = gpr_avl_add(avl, box(20), box(940), NULL); avl = remove_int(avl, 289); - avl = gpr_avl_add(avl, box(714), box(942)); - avl = gpr_avl_add(avl, box(584), box(943)); + avl = gpr_avl_add(avl, box(714), box(942), NULL); + avl = gpr_avl_add(avl, box(584), box(943), NULL); avl = remove_int(avl, 294); - avl = gpr_avl_add(avl, box(496), box(945)); - avl = gpr_avl_add(avl, box(394), box(946)); - avl = gpr_avl_add(avl, box(860), box(947)); - avl = gpr_avl_add(avl, box(58), box(948)); + avl = gpr_avl_add(avl, box(496), box(945), NULL); + avl = gpr_avl_add(avl, box(394), box(946), NULL); + avl = gpr_avl_add(avl, box(860), box(947), NULL); + avl = gpr_avl_add(avl, box(58), box(948), NULL); avl = remove_int(avl, 784); avl = remove_int(avl, 584); avl = remove_int(avl, 708); - avl = gpr_avl_add(avl, box(142), box(952)); - avl = gpr_avl_add(avl, box(247), box(953)); - avl = gpr_avl_add(avl, box(389), box(954)); + avl = gpr_avl_add(avl, box(142), box(952), NULL); + avl = gpr_avl_add(avl, box(247), box(953), NULL); + avl = gpr_avl_add(avl, box(389), box(954), NULL); avl = remove_int(avl, 390); - avl = gpr_avl_add(avl, box(465), box(956)); - avl = gpr_avl_add(avl, box(936), box(957)); - avl = gpr_avl_add(avl, box(309), box(958)); + avl = gpr_avl_add(avl, box(465), box(956), NULL); + avl = gpr_avl_add(avl, box(936), box(957), NULL); + avl = gpr_avl_add(avl, box(309), box(958), NULL); avl = remove_int(avl, 928); avl = remove_int(avl, 128); avl = remove_int(avl, 979); @@ -2102,15 +2104,15 @@ static void test_badcase3(void) { avl = remove_int(avl, 738); avl = remove_int(avl, 271); avl = remove_int(avl, 540); - avl = gpr_avl_add(avl, box(365), box(966)); + avl = gpr_avl_add(avl, box(365), box(966), NULL); avl = remove_int(avl, 82); - avl = gpr_avl_add(avl, box(728), box(968)); + avl = gpr_avl_add(avl, box(728), box(968), NULL); avl = remove_int(avl, 852); - avl = gpr_avl_add(avl, box(884), box(970)); - avl = gpr_avl_add(avl, box(502), box(971)); + avl = gpr_avl_add(avl, box(884), box(970), NULL); + avl = gpr_avl_add(avl, box(502), box(971), NULL); avl = remove_int(avl, 898); avl = remove_int(avl, 481); - avl = gpr_avl_add(avl, box(911), box(974)); + avl = gpr_avl_add(avl, box(911), box(974), NULL); avl = remove_int(avl, 787); avl = remove_int(avl, 785); avl = remove_int(avl, 537); @@ -2119,125 +2121,125 @@ static void test_badcase3(void) { avl = remove_int(avl, 749); avl = remove_int(avl, 637); avl = remove_int(avl, 900); - avl = gpr_avl_add(avl, box(598), box(983)); + avl = gpr_avl_add(avl, box(598), box(983), NULL); avl = remove_int(avl, 25); avl = remove_int(avl, 697); - avl = gpr_avl_add(avl, box(645), box(986)); - avl = gpr_avl_add(avl, box(211), box(987)); - avl = gpr_avl_add(avl, box(589), box(988)); + avl = gpr_avl_add(avl, box(645), box(986), NULL); + avl = gpr_avl_add(avl, box(211), box(987), NULL); + avl = gpr_avl_add(avl, box(589), box(988), NULL); avl = remove_int(avl, 702); - avl = gpr_avl_add(avl, box(53), box(990)); + avl = gpr_avl_add(avl, box(53), box(990), NULL); avl = remove_int(avl, 492); avl = remove_int(avl, 185); avl = remove_int(avl, 246); avl = remove_int(avl, 257); avl = remove_int(avl, 502); avl = remove_int(avl, 34); - avl = gpr_avl_add(avl, box(74), box(997)); - avl = gpr_avl_add(avl, box(834), box(998)); - avl = gpr_avl_add(avl, box(514), box(999)); - avl = gpr_avl_add(avl, box(75), box(1000)); + avl = gpr_avl_add(avl, box(74), box(997), NULL); + avl = gpr_avl_add(avl, box(834), box(998), NULL); + avl = gpr_avl_add(avl, box(514), box(999), NULL); + avl = gpr_avl_add(avl, box(75), box(1000), NULL); avl = remove_int(avl, 745); - avl = gpr_avl_add(avl, box(362), box(1002)); + avl = gpr_avl_add(avl, box(362), box(1002), NULL); avl = remove_int(avl, 215); - avl = gpr_avl_add(avl, box(624), box(1004)); + avl = gpr_avl_add(avl, box(624), box(1004), NULL); avl = remove_int(avl, 404); avl = remove_int(avl, 359); avl = remove_int(avl, 491); - avl = gpr_avl_add(avl, box(903), box(1008)); - avl = gpr_avl_add(avl, box(240), box(1009)); + avl = gpr_avl_add(avl, box(903), box(1008), NULL); + avl = gpr_avl_add(avl, box(240), box(1009), NULL); avl = remove_int(avl, 95); - avl = gpr_avl_add(avl, box(119), box(1011)); - avl = gpr_avl_add(avl, box(857), box(1012)); + avl = gpr_avl_add(avl, box(119), box(1011), NULL); + avl = gpr_avl_add(avl, box(857), box(1012), NULL); avl = remove_int(avl, 39); avl = remove_int(avl, 866); - avl = gpr_avl_add(avl, box(503), box(1015)); - avl = gpr_avl_add(avl, box(740), box(1016)); + avl = gpr_avl_add(avl, box(503), box(1015), NULL); + avl = gpr_avl_add(avl, box(740), box(1016), NULL); avl = remove_int(avl, 637); avl = remove_int(avl, 156); avl = remove_int(avl, 6); avl = remove_int(avl, 745); avl = remove_int(avl, 433); avl = remove_int(avl, 283); - avl = gpr_avl_add(avl, box(625), box(1023)); + avl = gpr_avl_add(avl, box(625), box(1023), NULL); avl = remove_int(avl, 638); - avl = gpr_avl_add(avl, box(299), box(1025)); - avl = gpr_avl_add(avl, box(584), box(1026)); + avl = gpr_avl_add(avl, box(299), box(1025), NULL); + avl = gpr_avl_add(avl, box(584), box(1026), NULL); avl = remove_int(avl, 863); - avl = gpr_avl_add(avl, box(612), box(1028)); - avl = gpr_avl_add(avl, box(62), box(1029)); - avl = gpr_avl_add(avl, box(432), box(1030)); + avl = gpr_avl_add(avl, box(612), box(1028), NULL); + avl = gpr_avl_add(avl, box(62), box(1029), NULL); + avl = gpr_avl_add(avl, box(432), box(1030), NULL); avl = remove_int(avl, 371); avl = remove_int(avl, 790); avl = remove_int(avl, 227); avl = remove_int(avl, 836); - avl = gpr_avl_add(avl, box(703), box(1035)); - avl = gpr_avl_add(avl, box(644), box(1036)); + avl = gpr_avl_add(avl, box(703), box(1035), NULL); + avl = gpr_avl_add(avl, box(644), box(1036), NULL); avl = remove_int(avl, 638); - avl = gpr_avl_add(avl, box(13), box(1038)); + avl = gpr_avl_add(avl, box(13), box(1038), NULL); avl = remove_int(avl, 66); avl = remove_int(avl, 82); - avl = gpr_avl_add(avl, box(362), box(1041)); - avl = gpr_avl_add(avl, box(783), box(1042)); + avl = gpr_avl_add(avl, box(362), box(1041), NULL); + avl = gpr_avl_add(avl, box(783), box(1042), NULL); avl = remove_int(avl, 60); - avl = gpr_avl_add(avl, box(80), box(1044)); - avl = gpr_avl_add(avl, box(825), box(1045)); - avl = gpr_avl_add(avl, box(688), box(1046)); - avl = gpr_avl_add(avl, box(662), box(1047)); + avl = gpr_avl_add(avl, box(80), box(1044), NULL); + avl = gpr_avl_add(avl, box(825), box(1045), NULL); + avl = gpr_avl_add(avl, box(688), box(1046), NULL); + avl = gpr_avl_add(avl, box(662), box(1047), NULL); avl = remove_int(avl, 156); avl = remove_int(avl, 376); avl = remove_int(avl, 99); - avl = gpr_avl_add(avl, box(526), box(1051)); - avl = gpr_avl_add(avl, box(168), box(1052)); + avl = gpr_avl_add(avl, box(526), box(1051), NULL); + avl = gpr_avl_add(avl, box(168), box(1052), NULL); avl = remove_int(avl, 646); avl = remove_int(avl, 380); avl = remove_int(avl, 833); - avl = gpr_avl_add(avl, box(53), box(1056)); + avl = gpr_avl_add(avl, box(53), box(1056), NULL); avl = remove_int(avl, 105); - avl = gpr_avl_add(avl, box(373), box(1058)); - avl = gpr_avl_add(avl, box(184), box(1059)); + avl = gpr_avl_add(avl, box(373), box(1058), NULL); + avl = gpr_avl_add(avl, box(184), box(1059), NULL); avl = remove_int(avl, 288); - avl = gpr_avl_add(avl, box(966), box(1061)); + avl = gpr_avl_add(avl, box(966), box(1061), NULL); avl = remove_int(avl, 158); - avl = gpr_avl_add(avl, box(406), box(1063)); + avl = gpr_avl_add(avl, box(406), box(1063), NULL); avl = remove_int(avl, 470); - avl = gpr_avl_add(avl, box(283), box(1065)); - avl = gpr_avl_add(avl, box(838), box(1066)); - avl = gpr_avl_add(avl, box(288), box(1067)); - avl = gpr_avl_add(avl, box(950), box(1068)); - avl = gpr_avl_add(avl, box(163), box(1069)); + avl = gpr_avl_add(avl, box(283), box(1065), NULL); + avl = gpr_avl_add(avl, box(838), box(1066), NULL); + avl = gpr_avl_add(avl, box(288), box(1067), NULL); + avl = gpr_avl_add(avl, box(950), box(1068), NULL); + avl = gpr_avl_add(avl, box(163), box(1069), NULL); avl = remove_int(avl, 623); avl = remove_int(avl, 769); - avl = gpr_avl_add(avl, box(144), box(1072)); - avl = gpr_avl_add(avl, box(489), box(1073)); + avl = gpr_avl_add(avl, box(144), box(1072), NULL); + avl = gpr_avl_add(avl, box(489), box(1073), NULL); avl = remove_int(avl, 15); - avl = gpr_avl_add(avl, box(971), box(1075)); + avl = gpr_avl_add(avl, box(971), box(1075), NULL); avl = remove_int(avl, 660); - avl = gpr_avl_add(avl, box(255), box(1077)); + avl = gpr_avl_add(avl, box(255), box(1077), NULL); avl = remove_int(avl, 494); - avl = gpr_avl_add(avl, box(109), box(1079)); - avl = gpr_avl_add(avl, box(420), box(1080)); - avl = gpr_avl_add(avl, box(509), box(1081)); + avl = gpr_avl_add(avl, box(109), box(1079), NULL); + avl = gpr_avl_add(avl, box(420), box(1080), NULL); + avl = gpr_avl_add(avl, box(509), box(1081), NULL); avl = remove_int(avl, 178); - avl = gpr_avl_add(avl, box(216), box(1083)); - avl = gpr_avl_add(avl, box(707), box(1084)); - avl = gpr_avl_add(avl, box(411), box(1085)); - avl = gpr_avl_add(avl, box(352), box(1086)); + avl = gpr_avl_add(avl, box(216), box(1083), NULL); + avl = gpr_avl_add(avl, box(707), box(1084), NULL); + avl = gpr_avl_add(avl, box(411), box(1085), NULL); + avl = gpr_avl_add(avl, box(352), box(1086), NULL); avl = remove_int(avl, 983); - avl = gpr_avl_add(avl, box(6), box(1088)); - avl = gpr_avl_add(avl, box(1014), box(1089)); + avl = gpr_avl_add(avl, box(6), box(1088), NULL); + avl = gpr_avl_add(avl, box(1014), box(1089), NULL); avl = remove_int(avl, 98); avl = remove_int(avl, 325); - avl = gpr_avl_add(avl, box(851), box(1092)); + avl = gpr_avl_add(avl, box(851), box(1092), NULL); avl = remove_int(avl, 553); - avl = gpr_avl_add(avl, box(218), box(1094)); - avl = gpr_avl_add(avl, box(261), box(1095)); + avl = gpr_avl_add(avl, box(218), box(1094), NULL); + avl = gpr_avl_add(avl, box(261), box(1095), NULL); avl = remove_int(avl, 31); - avl = gpr_avl_add(avl, box(872), box(1097)); + avl = gpr_avl_add(avl, box(872), box(1097), NULL); avl = remove_int(avl, 543); avl = remove_int(avl, 314); avl = remove_int(avl, 443); - avl = gpr_avl_add(avl, box(533), box(1101)); + avl = gpr_avl_add(avl, box(533), box(1101), NULL); avl = remove_int(avl, 881); avl = remove_int(avl, 269); avl = remove_int(avl, 940); @@ -2246,114 +2248,114 @@ static void test_badcase3(void) { avl = remove_int(avl, 773); avl = remove_int(avl, 790); avl = remove_int(avl, 345); - avl = gpr_avl_add(avl, box(965), box(1110)); + avl = gpr_avl_add(avl, box(965), box(1110), NULL); avl = remove_int(avl, 622); - avl = gpr_avl_add(avl, box(352), box(1112)); + avl = gpr_avl_add(avl, box(352), box(1112), NULL); avl = remove_int(avl, 182); - avl = gpr_avl_add(avl, box(534), box(1114)); - avl = gpr_avl_add(avl, box(97), box(1115)); - avl = gpr_avl_add(avl, box(198), box(1116)); + avl = gpr_avl_add(avl, box(534), box(1114), NULL); + avl = gpr_avl_add(avl, box(97), box(1115), NULL); + avl = gpr_avl_add(avl, box(198), box(1116), NULL); avl = remove_int(avl, 750); - avl = gpr_avl_add(avl, box(98), box(1118)); + avl = gpr_avl_add(avl, box(98), box(1118), NULL); avl = remove_int(avl, 943); - avl = gpr_avl_add(avl, box(254), box(1120)); - avl = gpr_avl_add(avl, box(30), box(1121)); + avl = gpr_avl_add(avl, box(254), box(1120), NULL); + avl = gpr_avl_add(avl, box(30), box(1121), NULL); avl = remove_int(avl, 14); avl = remove_int(avl, 475); avl = remove_int(avl, 82); - avl = gpr_avl_add(avl, box(789), box(1125)); - avl = gpr_avl_add(avl, box(402), box(1126)); + avl = gpr_avl_add(avl, box(789), box(1125), NULL); + avl = gpr_avl_add(avl, box(402), box(1126), NULL); avl = remove_int(avl, 1019); - avl = gpr_avl_add(avl, box(858), box(1128)); - avl = gpr_avl_add(avl, box(625), box(1129)); + avl = gpr_avl_add(avl, box(858), box(1128), NULL); + avl = gpr_avl_add(avl, box(625), box(1129), NULL); avl = remove_int(avl, 675); avl = remove_int(avl, 323); - avl = gpr_avl_add(avl, box(329), box(1132)); + avl = gpr_avl_add(avl, box(329), box(1132), NULL); avl = remove_int(avl, 929); avl = remove_int(avl, 44); - avl = gpr_avl_add(avl, box(443), box(1135)); - avl = gpr_avl_add(avl, box(653), box(1136)); - avl = gpr_avl_add(avl, box(750), box(1137)); - avl = gpr_avl_add(avl, box(252), box(1138)); - avl = gpr_avl_add(avl, box(449), box(1139)); + avl = gpr_avl_add(avl, box(443), box(1135), NULL); + avl = gpr_avl_add(avl, box(653), box(1136), NULL); + avl = gpr_avl_add(avl, box(750), box(1137), NULL); + avl = gpr_avl_add(avl, box(252), box(1138), NULL); + avl = gpr_avl_add(avl, box(449), box(1139), NULL); avl = remove_int(avl, 1022); avl = remove_int(avl, 357); avl = remove_int(avl, 602); avl = remove_int(avl, 131); - avl = gpr_avl_add(avl, box(531), box(1144)); + avl = gpr_avl_add(avl, box(531), box(1144), NULL); avl = remove_int(avl, 806); - avl = gpr_avl_add(avl, box(455), box(1146)); + avl = gpr_avl_add(avl, box(455), box(1146), NULL); avl = remove_int(avl, 31); - avl = gpr_avl_add(avl, box(154), box(1148)); - avl = gpr_avl_add(avl, box(189), box(1149)); + avl = gpr_avl_add(avl, box(154), box(1148), NULL); + avl = gpr_avl_add(avl, box(189), box(1149), NULL); avl = remove_int(avl, 786); - avl = gpr_avl_add(avl, box(496), box(1151)); - avl = gpr_avl_add(avl, box(81), box(1152)); - avl = gpr_avl_add(avl, box(59), box(1153)); + avl = gpr_avl_add(avl, box(496), box(1151), NULL); + avl = gpr_avl_add(avl, box(81), box(1152), NULL); + avl = gpr_avl_add(avl, box(59), box(1153), NULL); avl = remove_int(avl, 424); avl = remove_int(avl, 668); - avl = gpr_avl_add(avl, box(723), box(1156)); - avl = gpr_avl_add(avl, box(822), box(1157)); - avl = gpr_avl_add(avl, box(354), box(1158)); + avl = gpr_avl_add(avl, box(723), box(1156), NULL); + avl = gpr_avl_add(avl, box(822), box(1157), NULL); + avl = gpr_avl_add(avl, box(354), box(1158), NULL); avl = remove_int(avl, 738); - avl = gpr_avl_add(avl, box(686), box(1160)); - avl = gpr_avl_add(avl, box(43), box(1161)); - avl = gpr_avl_add(avl, box(625), box(1162)); - avl = gpr_avl_add(avl, box(902), box(1163)); - avl = gpr_avl_add(avl, box(12), box(1164)); - avl = gpr_avl_add(avl, box(977), box(1165)); - avl = gpr_avl_add(avl, box(699), box(1166)); - avl = gpr_avl_add(avl, box(189), box(1167)); + avl = gpr_avl_add(avl, box(686), box(1160), NULL); + avl = gpr_avl_add(avl, box(43), box(1161), NULL); + avl = gpr_avl_add(avl, box(625), box(1162), NULL); + avl = gpr_avl_add(avl, box(902), box(1163), NULL); + avl = gpr_avl_add(avl, box(12), box(1164), NULL); + avl = gpr_avl_add(avl, box(977), box(1165), NULL); + avl = gpr_avl_add(avl, box(699), box(1166), NULL); + avl = gpr_avl_add(avl, box(189), box(1167), NULL); avl = remove_int(avl, 672); avl = remove_int(avl, 90); avl = remove_int(avl, 757); avl = remove_int(avl, 494); - avl = gpr_avl_add(avl, box(759), box(1172)); + avl = gpr_avl_add(avl, box(759), box(1172), NULL); avl = remove_int(avl, 758); avl = remove_int(avl, 222); - avl = gpr_avl_add(avl, box(975), box(1175)); + avl = gpr_avl_add(avl, box(975), box(1175), NULL); avl = remove_int(avl, 993); - avl = gpr_avl_add(avl, box(2), box(1177)); - avl = gpr_avl_add(avl, box(70), box(1178)); + avl = gpr_avl_add(avl, box(2), box(1177), NULL); + avl = gpr_avl_add(avl, box(70), box(1178), NULL); avl = remove_int(avl, 350); avl = remove_int(avl, 972); avl = remove_int(avl, 880); - avl = gpr_avl_add(avl, box(753), box(1182)); + avl = gpr_avl_add(avl, box(753), box(1182), NULL); avl = remove_int(avl, 404); - avl = gpr_avl_add(avl, box(294), box(1184)); + avl = gpr_avl_add(avl, box(294), box(1184), NULL); avl = remove_int(avl, 474); - avl = gpr_avl_add(avl, box(228), box(1186)); - avl = gpr_avl_add(avl, box(484), box(1187)); + avl = gpr_avl_add(avl, box(228), box(1186), NULL); + avl = gpr_avl_add(avl, box(484), box(1187), NULL); avl = remove_int(avl, 238); avl = remove_int(avl, 53); avl = remove_int(avl, 691); - avl = gpr_avl_add(avl, box(345), box(1191)); + avl = gpr_avl_add(avl, box(345), box(1191), NULL); avl = remove_int(avl, 0); - avl = gpr_avl_add(avl, box(230), box(1193)); + avl = gpr_avl_add(avl, box(230), box(1193), NULL); avl = remove_int(avl, 227); avl = remove_int(avl, 152); - avl = gpr_avl_add(avl, box(884), box(1196)); + avl = gpr_avl_add(avl, box(884), box(1196), NULL); avl = remove_int(avl, 823); avl = remove_int(avl, 53); - avl = gpr_avl_add(avl, box(1015), box(1199)); - avl = gpr_avl_add(avl, box(697), box(1200)); - avl = gpr_avl_add(avl, box(376), box(1201)); + avl = gpr_avl_add(avl, box(1015), box(1199), NULL); + avl = gpr_avl_add(avl, box(697), box(1200), NULL); + avl = gpr_avl_add(avl, box(376), box(1201), NULL); avl = remove_int(avl, 411); - avl = gpr_avl_add(avl, box(888), box(1203)); + avl = gpr_avl_add(avl, box(888), box(1203), NULL); avl = remove_int(avl, 55); - avl = gpr_avl_add(avl, box(85), box(1205)); + avl = gpr_avl_add(avl, box(85), box(1205), NULL); avl = remove_int(avl, 947); avl = remove_int(avl, 382); avl = remove_int(avl, 777); - avl = gpr_avl_add(avl, box(1017), box(1209)); - avl = gpr_avl_add(avl, box(169), box(1210)); - avl = gpr_avl_add(avl, box(156), box(1211)); + avl = gpr_avl_add(avl, box(1017), box(1209), NULL); + avl = gpr_avl_add(avl, box(169), box(1210), NULL); + avl = gpr_avl_add(avl, box(156), box(1211), NULL); avl = remove_int(avl, 153); avl = remove_int(avl, 642); avl = remove_int(avl, 158); - avl = gpr_avl_add(avl, box(554), box(1215)); - avl = gpr_avl_add(avl, box(76), box(1216)); - avl = gpr_avl_add(avl, box(756), box(1217)); + avl = gpr_avl_add(avl, box(554), box(1215), NULL); + avl = gpr_avl_add(avl, box(76), box(1216), NULL); + avl = gpr_avl_add(avl, box(756), box(1217), NULL); avl = remove_int(avl, 767); avl = remove_int(avl, 112); avl = remove_int(avl, 539); @@ -2362,37 +2364,37 @@ static void test_badcase3(void) { avl = remove_int(avl, 385); avl = remove_int(avl, 514); avl = remove_int(avl, 362); - avl = gpr_avl_add(avl, box(523), box(1226)); - avl = gpr_avl_add(avl, box(712), box(1227)); - avl = gpr_avl_add(avl, box(474), box(1228)); - avl = gpr_avl_add(avl, box(882), box(1229)); - avl = gpr_avl_add(avl, box(965), box(1230)); + avl = gpr_avl_add(avl, box(523), box(1226), NULL); + avl = gpr_avl_add(avl, box(712), box(1227), NULL); + avl = gpr_avl_add(avl, box(474), box(1228), NULL); + avl = gpr_avl_add(avl, box(882), box(1229), NULL); + avl = gpr_avl_add(avl, box(965), box(1230), NULL); avl = remove_int(avl, 464); - avl = gpr_avl_add(avl, box(319), box(1232)); - avl = gpr_avl_add(avl, box(504), box(1233)); + avl = gpr_avl_add(avl, box(319), box(1232), NULL); + avl = gpr_avl_add(avl, box(504), box(1233), NULL); avl = remove_int(avl, 818); - avl = gpr_avl_add(avl, box(884), box(1235)); - avl = gpr_avl_add(avl, box(813), box(1236)); - avl = gpr_avl_add(avl, box(795), box(1237)); + avl = gpr_avl_add(avl, box(884), box(1235), NULL); + avl = gpr_avl_add(avl, box(813), box(1236), NULL); + avl = gpr_avl_add(avl, box(795), box(1237), NULL); avl = remove_int(avl, 306); - avl = gpr_avl_add(avl, box(799), box(1239)); + avl = gpr_avl_add(avl, box(799), box(1239), NULL); avl = remove_int(avl, 534); - avl = gpr_avl_add(avl, box(480), box(1241)); - avl = gpr_avl_add(avl, box(656), box(1242)); - avl = gpr_avl_add(avl, box(709), box(1243)); - avl = gpr_avl_add(avl, box(500), box(1244)); + avl = gpr_avl_add(avl, box(480), box(1241), NULL); + avl = gpr_avl_add(avl, box(656), box(1242), NULL); + avl = gpr_avl_add(avl, box(709), box(1243), NULL); + avl = gpr_avl_add(avl, box(500), box(1244), NULL); avl = remove_int(avl, 740); - avl = gpr_avl_add(avl, box(980), box(1246)); - avl = gpr_avl_add(avl, box(458), box(1247)); + avl = gpr_avl_add(avl, box(980), box(1246), NULL); + avl = gpr_avl_add(avl, box(458), box(1247), NULL); avl = remove_int(avl, 377); avl = remove_int(avl, 338); - avl = gpr_avl_add(avl, box(554), box(1250)); - avl = gpr_avl_add(avl, box(504), box(1251)); - avl = gpr_avl_add(avl, box(603), box(1252)); - avl = gpr_avl_add(avl, box(761), box(1253)); + avl = gpr_avl_add(avl, box(554), box(1250), NULL); + avl = gpr_avl_add(avl, box(504), box(1251), NULL); + avl = gpr_avl_add(avl, box(603), box(1252), NULL); + avl = gpr_avl_add(avl, box(761), box(1253), NULL); avl = remove_int(avl, 431); - avl = gpr_avl_add(avl, box(707), box(1255)); - avl = gpr_avl_add(avl, box(673), box(1256)); + avl = gpr_avl_add(avl, box(707), box(1255), NULL); + avl = gpr_avl_add(avl, box(673), box(1256), NULL); avl = remove_int(avl, 998); avl = remove_int(avl, 332); avl = remove_int(avl, 413); @@ -2400,448 +2402,448 @@ static void test_badcase3(void) { avl = remove_int(avl, 249); avl = remove_int(avl, 309); avl = remove_int(avl, 459); - avl = gpr_avl_add(avl, box(645), box(1264)); + avl = gpr_avl_add(avl, box(645), box(1264), NULL); avl = remove_int(avl, 858); avl = remove_int(avl, 997); - avl = gpr_avl_add(avl, box(519), box(1267)); + avl = gpr_avl_add(avl, box(519), box(1267), NULL); avl = remove_int(avl, 614); avl = remove_int(avl, 462); avl = remove_int(avl, 792); - avl = gpr_avl_add(avl, box(987), box(1271)); - avl = gpr_avl_add(avl, box(309), box(1272)); + avl = gpr_avl_add(avl, box(987), box(1271), NULL); + avl = gpr_avl_add(avl, box(309), box(1272), NULL); avl = remove_int(avl, 747); - avl = gpr_avl_add(avl, box(621), box(1274)); - avl = gpr_avl_add(avl, box(450), box(1275)); + avl = gpr_avl_add(avl, box(621), box(1274), NULL); + avl = gpr_avl_add(avl, box(450), box(1275), NULL); avl = remove_int(avl, 265); avl = remove_int(avl, 8); avl = remove_int(avl, 383); - avl = gpr_avl_add(avl, box(238), box(1279)); + avl = gpr_avl_add(avl, box(238), box(1279), NULL); avl = remove_int(avl, 241); - avl = gpr_avl_add(avl, box(180), box(1281)); - avl = gpr_avl_add(avl, box(411), box(1282)); - avl = gpr_avl_add(avl, box(791), box(1283)); - avl = gpr_avl_add(avl, box(955), box(1284)); + avl = gpr_avl_add(avl, box(180), box(1281), NULL); + avl = gpr_avl_add(avl, box(411), box(1282), NULL); + avl = gpr_avl_add(avl, box(791), box(1283), NULL); + avl = gpr_avl_add(avl, box(955), box(1284), NULL); avl = remove_int(avl, 24); avl = remove_int(avl, 375); - avl = gpr_avl_add(avl, box(140), box(1287)); + avl = gpr_avl_add(avl, box(140), box(1287), NULL); avl = remove_int(avl, 949); - avl = gpr_avl_add(avl, box(301), box(1289)); - avl = gpr_avl_add(avl, box(0), box(1290)); + avl = gpr_avl_add(avl, box(301), box(1289), NULL); + avl = gpr_avl_add(avl, box(0), box(1290), NULL); avl = remove_int(avl, 371); avl = remove_int(avl, 427); avl = remove_int(avl, 841); avl = remove_int(avl, 847); - avl = gpr_avl_add(avl, box(814), box(1295)); - avl = gpr_avl_add(avl, box(127), box(1296)); - avl = gpr_avl_add(avl, box(279), box(1297)); + avl = gpr_avl_add(avl, box(814), box(1295), NULL); + avl = gpr_avl_add(avl, box(127), box(1296), NULL); + avl = gpr_avl_add(avl, box(279), box(1297), NULL); avl = remove_int(avl, 669); avl = remove_int(avl, 541); avl = remove_int(avl, 275); avl = remove_int(avl, 299); avl = remove_int(avl, 552); - avl = gpr_avl_add(avl, box(310), box(1303)); - avl = gpr_avl_add(avl, box(304), box(1304)); - avl = gpr_avl_add(avl, box(1), box(1305)); - avl = gpr_avl_add(avl, box(339), box(1306)); + avl = gpr_avl_add(avl, box(310), box(1303), NULL); + avl = gpr_avl_add(avl, box(304), box(1304), NULL); + avl = gpr_avl_add(avl, box(1), box(1305), NULL); + avl = gpr_avl_add(avl, box(339), box(1306), NULL); avl = remove_int(avl, 570); avl = remove_int(avl, 752); avl = remove_int(avl, 552); avl = remove_int(avl, 442); avl = remove_int(avl, 639); - avl = gpr_avl_add(avl, box(313), box(1312)); + avl = gpr_avl_add(avl, box(313), box(1312), NULL); avl = remove_int(avl, 85); - avl = gpr_avl_add(avl, box(964), box(1314)); - avl = gpr_avl_add(avl, box(559), box(1315)); + avl = gpr_avl_add(avl, box(964), box(1314), NULL); + avl = gpr_avl_add(avl, box(559), box(1315), NULL); avl = remove_int(avl, 167); - avl = gpr_avl_add(avl, box(866), box(1317)); + avl = gpr_avl_add(avl, box(866), box(1317), NULL); avl = remove_int(avl, 275); - avl = gpr_avl_add(avl, box(173), box(1319)); - avl = gpr_avl_add(avl, box(765), box(1320)); + avl = gpr_avl_add(avl, box(173), box(1319), NULL); + avl = gpr_avl_add(avl, box(765), box(1320), NULL); avl = remove_int(avl, 883); - avl = gpr_avl_add(avl, box(547), box(1322)); - avl = gpr_avl_add(avl, box(847), box(1323)); + avl = gpr_avl_add(avl, box(547), box(1322), NULL); + avl = gpr_avl_add(avl, box(847), box(1323), NULL); avl = remove_int(avl, 817); avl = remove_int(avl, 850); avl = remove_int(avl, 718); - avl = gpr_avl_add(avl, box(806), box(1327)); - avl = gpr_avl_add(avl, box(360), box(1328)); + avl = gpr_avl_add(avl, box(806), box(1327), NULL); + avl = gpr_avl_add(avl, box(360), box(1328), NULL); avl = remove_int(avl, 991); - avl = gpr_avl_add(avl, box(493), box(1330)); + avl = gpr_avl_add(avl, box(493), box(1330), NULL); avl = remove_int(avl, 516); - avl = gpr_avl_add(avl, box(361), box(1332)); + avl = gpr_avl_add(avl, box(361), box(1332), NULL); avl = remove_int(avl, 355); - avl = gpr_avl_add(avl, box(512), box(1334)); - avl = gpr_avl_add(avl, box(191), box(1335)); + avl = gpr_avl_add(avl, box(512), box(1334), NULL); + avl = gpr_avl_add(avl, box(191), box(1335), NULL); avl = remove_int(avl, 703); - avl = gpr_avl_add(avl, box(333), box(1337)); + avl = gpr_avl_add(avl, box(333), box(1337), NULL); avl = remove_int(avl, 481); - avl = gpr_avl_add(avl, box(501), box(1339)); + avl = gpr_avl_add(avl, box(501), box(1339), NULL); avl = remove_int(avl, 532); avl = remove_int(avl, 510); - avl = gpr_avl_add(avl, box(793), box(1342)); - avl = gpr_avl_add(avl, box(234), box(1343)); + avl = gpr_avl_add(avl, box(793), box(1342), NULL); + avl = gpr_avl_add(avl, box(234), box(1343), NULL); avl = remove_int(avl, 159); avl = remove_int(avl, 429); avl = remove_int(avl, 728); avl = remove_int(avl, 288); - avl = gpr_avl_add(avl, box(281), box(1348)); - avl = gpr_avl_add(avl, box(702), box(1349)); - avl = gpr_avl_add(avl, box(149), box(1350)); + avl = gpr_avl_add(avl, box(281), box(1348), NULL); + avl = gpr_avl_add(avl, box(702), box(1349), NULL); + avl = gpr_avl_add(avl, box(149), box(1350), NULL); avl = remove_int(avl, 22); avl = remove_int(avl, 944); avl = remove_int(avl, 55); avl = remove_int(avl, 512); avl = remove_int(avl, 676); avl = remove_int(avl, 884); - avl = gpr_avl_add(avl, box(246), box(1357)); - avl = gpr_avl_add(avl, box(455), box(1358)); + avl = gpr_avl_add(avl, box(246), box(1357), NULL); + avl = gpr_avl_add(avl, box(455), box(1358), NULL); avl = remove_int(avl, 782); avl = remove_int(avl, 682); - avl = gpr_avl_add(avl, box(243), box(1361)); - avl = gpr_avl_add(avl, box(109), box(1362)); - avl = gpr_avl_add(avl, box(452), box(1363)); + avl = gpr_avl_add(avl, box(243), box(1361), NULL); + avl = gpr_avl_add(avl, box(109), box(1362), NULL); + avl = gpr_avl_add(avl, box(452), box(1363), NULL); avl = remove_int(avl, 151); - avl = gpr_avl_add(avl, box(159), box(1365)); + avl = gpr_avl_add(avl, box(159), box(1365), NULL); avl = remove_int(avl, 1023); - avl = gpr_avl_add(avl, box(129), box(1367)); - avl = gpr_avl_add(avl, box(537), box(1368)); + avl = gpr_avl_add(avl, box(129), box(1367), NULL); + avl = gpr_avl_add(avl, box(537), box(1368), NULL); avl = remove_int(avl, 321); - avl = gpr_avl_add(avl, box(740), box(1370)); + avl = gpr_avl_add(avl, box(740), box(1370), NULL); avl = remove_int(avl, 45); avl = remove_int(avl, 136); - avl = gpr_avl_add(avl, box(229), box(1373)); + avl = gpr_avl_add(avl, box(229), box(1373), NULL); avl = remove_int(avl, 772); - avl = gpr_avl_add(avl, box(181), box(1375)); + avl = gpr_avl_add(avl, box(181), box(1375), NULL); avl = remove_int(avl, 175); - avl = gpr_avl_add(avl, box(817), box(1377)); + avl = gpr_avl_add(avl, box(817), box(1377), NULL); avl = remove_int(avl, 956); - avl = gpr_avl_add(avl, box(675), box(1379)); - avl = gpr_avl_add(avl, box(375), box(1380)); + avl = gpr_avl_add(avl, box(675), box(1379), NULL); + avl = gpr_avl_add(avl, box(375), box(1380), NULL); avl = remove_int(avl, 384); - avl = gpr_avl_add(avl, box(1016), box(1382)); + avl = gpr_avl_add(avl, box(1016), box(1382), NULL); avl = remove_int(avl, 295); avl = remove_int(avl, 697); avl = remove_int(avl, 554); avl = remove_int(avl, 590); avl = remove_int(avl, 1014); - avl = gpr_avl_add(avl, box(890), box(1388)); - avl = gpr_avl_add(avl, box(293), box(1389)); + avl = gpr_avl_add(avl, box(890), box(1388), NULL); + avl = gpr_avl_add(avl, box(293), box(1389), NULL); avl = remove_int(avl, 207); avl = remove_int(avl, 46); - avl = gpr_avl_add(avl, box(899), box(1392)); - avl = gpr_avl_add(avl, box(666), box(1393)); - avl = gpr_avl_add(avl, box(85), box(1394)); - avl = gpr_avl_add(avl, box(914), box(1395)); - avl = gpr_avl_add(avl, box(128), box(1396)); - avl = gpr_avl_add(avl, box(835), box(1397)); - avl = gpr_avl_add(avl, box(787), box(1398)); - avl = gpr_avl_add(avl, box(649), box(1399)); - avl = gpr_avl_add(avl, box(723), box(1400)); + avl = gpr_avl_add(avl, box(899), box(1392), NULL); + avl = gpr_avl_add(avl, box(666), box(1393), NULL); + avl = gpr_avl_add(avl, box(85), box(1394), NULL); + avl = gpr_avl_add(avl, box(914), box(1395), NULL); + avl = gpr_avl_add(avl, box(128), box(1396), NULL); + avl = gpr_avl_add(avl, box(835), box(1397), NULL); + avl = gpr_avl_add(avl, box(787), box(1398), NULL); + avl = gpr_avl_add(avl, box(649), box(1399), NULL); + avl = gpr_avl_add(avl, box(723), box(1400), NULL); avl = remove_int(avl, 874); - avl = gpr_avl_add(avl, box(778), box(1402)); - avl = gpr_avl_add(avl, box(1015), box(1403)); - avl = gpr_avl_add(avl, box(59), box(1404)); - avl = gpr_avl_add(avl, box(259), box(1405)); - avl = gpr_avl_add(avl, box(758), box(1406)); + avl = gpr_avl_add(avl, box(778), box(1402), NULL); + avl = gpr_avl_add(avl, box(1015), box(1403), NULL); + avl = gpr_avl_add(avl, box(59), box(1404), NULL); + avl = gpr_avl_add(avl, box(259), box(1405), NULL); + avl = gpr_avl_add(avl, box(758), box(1406), NULL); avl = remove_int(avl, 648); - avl = gpr_avl_add(avl, box(145), box(1408)); - avl = gpr_avl_add(avl, box(440), box(1409)); + avl = gpr_avl_add(avl, box(145), box(1408), NULL); + avl = gpr_avl_add(avl, box(440), box(1409), NULL); avl = remove_int(avl, 608); avl = remove_int(avl, 690); - avl = gpr_avl_add(avl, box(605), box(1412)); + avl = gpr_avl_add(avl, box(605), box(1412), NULL); avl = remove_int(avl, 856); avl = remove_int(avl, 608); - avl = gpr_avl_add(avl, box(829), box(1415)); - avl = gpr_avl_add(avl, box(660), box(1416)); + avl = gpr_avl_add(avl, box(829), box(1415), NULL); + avl = gpr_avl_add(avl, box(660), box(1416), NULL); avl = remove_int(avl, 596); - avl = gpr_avl_add(avl, box(519), box(1418)); - avl = gpr_avl_add(avl, box(35), box(1419)); - avl = gpr_avl_add(avl, box(871), box(1420)); + avl = gpr_avl_add(avl, box(519), box(1418), NULL); + avl = gpr_avl_add(avl, box(35), box(1419), NULL); + avl = gpr_avl_add(avl, box(871), box(1420), NULL); avl = remove_int(avl, 845); - avl = gpr_avl_add(avl, box(600), box(1422)); - avl = gpr_avl_add(avl, box(215), box(1423)); + avl = gpr_avl_add(avl, box(600), box(1422), NULL); + avl = gpr_avl_add(avl, box(215), box(1423), NULL); avl = remove_int(avl, 761); - avl = gpr_avl_add(avl, box(975), box(1425)); + avl = gpr_avl_add(avl, box(975), box(1425), NULL); avl = remove_int(avl, 987); - avl = gpr_avl_add(avl, box(58), box(1427)); + avl = gpr_avl_add(avl, box(58), box(1427), NULL); avl = remove_int(avl, 119); - avl = gpr_avl_add(avl, box(937), box(1429)); - avl = gpr_avl_add(avl, box(372), box(1430)); - avl = gpr_avl_add(avl, box(11), box(1431)); - avl = gpr_avl_add(avl, box(398), box(1432)); - avl = gpr_avl_add(avl, box(423), box(1433)); + avl = gpr_avl_add(avl, box(937), box(1429), NULL); + avl = gpr_avl_add(avl, box(372), box(1430), NULL); + avl = gpr_avl_add(avl, box(11), box(1431), NULL); + avl = gpr_avl_add(avl, box(398), box(1432), NULL); + avl = gpr_avl_add(avl, box(423), box(1433), NULL); avl = remove_int(avl, 171); - avl = gpr_avl_add(avl, box(473), box(1435)); + avl = gpr_avl_add(avl, box(473), box(1435), NULL); avl = remove_int(avl, 752); avl = remove_int(avl, 625); avl = remove_int(avl, 764); avl = remove_int(avl, 49); - avl = gpr_avl_add(avl, box(472), box(1440)); + avl = gpr_avl_add(avl, box(472), box(1440), NULL); avl = remove_int(avl, 847); avl = remove_int(avl, 642); avl = remove_int(avl, 1004); avl = remove_int(avl, 795); avl = remove_int(avl, 465); - avl = gpr_avl_add(avl, box(636), box(1446)); + avl = gpr_avl_add(avl, box(636), box(1446), NULL); avl = remove_int(avl, 152); - avl = gpr_avl_add(avl, box(61), box(1448)); + avl = gpr_avl_add(avl, box(61), box(1448), NULL); avl = remove_int(avl, 929); avl = remove_int(avl, 9); - avl = gpr_avl_add(avl, box(251), box(1451)); - avl = gpr_avl_add(avl, box(672), box(1452)); - avl = gpr_avl_add(avl, box(66), box(1453)); + avl = gpr_avl_add(avl, box(251), box(1451), NULL); + avl = gpr_avl_add(avl, box(672), box(1452), NULL); + avl = gpr_avl_add(avl, box(66), box(1453), NULL); avl = remove_int(avl, 693); avl = remove_int(avl, 914); avl = remove_int(avl, 116); avl = remove_int(avl, 577); - avl = gpr_avl_add(avl, box(618), box(1458)); - avl = gpr_avl_add(avl, box(495), box(1459)); + avl = gpr_avl_add(avl, box(618), box(1458), NULL); + avl = gpr_avl_add(avl, box(495), box(1459), NULL); avl = remove_int(avl, 450); - avl = gpr_avl_add(avl, box(533), box(1461)); - avl = gpr_avl_add(avl, box(414), box(1462)); + avl = gpr_avl_add(avl, box(533), box(1461), NULL); + avl = gpr_avl_add(avl, box(414), box(1462), NULL); avl = remove_int(avl, 74); avl = remove_int(avl, 236); - avl = gpr_avl_add(avl, box(707), box(1465)); - avl = gpr_avl_add(avl, box(357), box(1466)); - avl = gpr_avl_add(avl, box(1007), box(1467)); - avl = gpr_avl_add(avl, box(811), box(1468)); - avl = gpr_avl_add(avl, box(418), box(1469)); - avl = gpr_avl_add(avl, box(164), box(1470)); - avl = gpr_avl_add(avl, box(622), box(1471)); + avl = gpr_avl_add(avl, box(707), box(1465), NULL); + avl = gpr_avl_add(avl, box(357), box(1466), NULL); + avl = gpr_avl_add(avl, box(1007), box(1467), NULL); + avl = gpr_avl_add(avl, box(811), box(1468), NULL); + avl = gpr_avl_add(avl, box(418), box(1469), NULL); + avl = gpr_avl_add(avl, box(164), box(1470), NULL); + avl = gpr_avl_add(avl, box(622), box(1471), NULL); avl = remove_int(avl, 22); avl = remove_int(avl, 14); avl = remove_int(avl, 732); avl = remove_int(avl, 7); avl = remove_int(avl, 447); - avl = gpr_avl_add(avl, box(221), box(1477)); - avl = gpr_avl_add(avl, box(202), box(1478)); - avl = gpr_avl_add(avl, box(312), box(1479)); + avl = gpr_avl_add(avl, box(221), box(1477), NULL); + avl = gpr_avl_add(avl, box(202), box(1478), NULL); + avl = gpr_avl_add(avl, box(312), box(1479), NULL); avl = remove_int(avl, 274); - avl = gpr_avl_add(avl, box(684), box(1481)); - avl = gpr_avl_add(avl, box(954), box(1482)); - avl = gpr_avl_add(avl, box(637), box(1483)); + avl = gpr_avl_add(avl, box(684), box(1481), NULL); + avl = gpr_avl_add(avl, box(954), box(1482), NULL); + avl = gpr_avl_add(avl, box(637), box(1483), NULL); avl = remove_int(avl, 716); - avl = gpr_avl_add(avl, box(198), box(1485)); + avl = gpr_avl_add(avl, box(198), box(1485), NULL); avl = remove_int(avl, 340); avl = remove_int(avl, 137); avl = remove_int(avl, 995); avl = remove_int(avl, 1004); - avl = gpr_avl_add(avl, box(661), box(1490)); - avl = gpr_avl_add(avl, box(862), box(1491)); + avl = gpr_avl_add(avl, box(661), box(1490), NULL); + avl = gpr_avl_add(avl, box(862), box(1491), NULL); avl = remove_int(avl, 527); - avl = gpr_avl_add(avl, box(945), box(1493)); + avl = gpr_avl_add(avl, box(945), box(1493), NULL); avl = remove_int(avl, 355); avl = remove_int(avl, 144); - avl = gpr_avl_add(avl, box(229), box(1496)); - avl = gpr_avl_add(avl, box(237), box(1497)); + avl = gpr_avl_add(avl, box(229), box(1496), NULL); + avl = gpr_avl_add(avl, box(237), box(1497), NULL); avl = remove_int(avl, 471); avl = remove_int(avl, 901); - avl = gpr_avl_add(avl, box(905), box(1500)); + avl = gpr_avl_add(avl, box(905), box(1500), NULL); avl = remove_int(avl, 19); avl = remove_int(avl, 896); avl = remove_int(avl, 585); avl = remove_int(avl, 308); - avl = gpr_avl_add(avl, box(547), box(1505)); - avl = gpr_avl_add(avl, box(552), box(1506)); - avl = gpr_avl_add(avl, box(30), box(1507)); - avl = gpr_avl_add(avl, box(445), box(1508)); + avl = gpr_avl_add(avl, box(547), box(1505), NULL); + avl = gpr_avl_add(avl, box(552), box(1506), NULL); + avl = gpr_avl_add(avl, box(30), box(1507), NULL); + avl = gpr_avl_add(avl, box(445), box(1508), NULL); avl = remove_int(avl, 785); avl = remove_int(avl, 185); - avl = gpr_avl_add(avl, box(405), box(1511)); - avl = gpr_avl_add(avl, box(733), box(1512)); - avl = gpr_avl_add(avl, box(573), box(1513)); - avl = gpr_avl_add(avl, box(492), box(1514)); - avl = gpr_avl_add(avl, box(343), box(1515)); - avl = gpr_avl_add(avl, box(527), box(1516)); - avl = gpr_avl_add(avl, box(596), box(1517)); - avl = gpr_avl_add(avl, box(519), box(1518)); + avl = gpr_avl_add(avl, box(405), box(1511), NULL); + avl = gpr_avl_add(avl, box(733), box(1512), NULL); + avl = gpr_avl_add(avl, box(573), box(1513), NULL); + avl = gpr_avl_add(avl, box(492), box(1514), NULL); + avl = gpr_avl_add(avl, box(343), box(1515), NULL); + avl = gpr_avl_add(avl, box(527), box(1516), NULL); + avl = gpr_avl_add(avl, box(596), box(1517), NULL); + avl = gpr_avl_add(avl, box(519), box(1518), NULL); avl = remove_int(avl, 243); avl = remove_int(avl, 722); - avl = gpr_avl_add(avl, box(772), box(1521)); + avl = gpr_avl_add(avl, box(772), box(1521), NULL); avl = remove_int(avl, 152); avl = remove_int(avl, 305); - avl = gpr_avl_add(avl, box(754), box(1524)); - avl = gpr_avl_add(avl, box(373), box(1525)); + avl = gpr_avl_add(avl, box(754), box(1524), NULL); + avl = gpr_avl_add(avl, box(373), box(1525), NULL); avl = remove_int(avl, 995); - avl = gpr_avl_add(avl, box(329), box(1527)); + avl = gpr_avl_add(avl, box(329), box(1527), NULL); avl = remove_int(avl, 397); - avl = gpr_avl_add(avl, box(884), box(1529)); + avl = gpr_avl_add(avl, box(884), box(1529), NULL); avl = remove_int(avl, 329); avl = remove_int(avl, 240); - avl = gpr_avl_add(avl, box(566), box(1532)); - avl = gpr_avl_add(avl, box(232), box(1533)); + avl = gpr_avl_add(avl, box(566), box(1532), NULL); + avl = gpr_avl_add(avl, box(232), box(1533), NULL); avl = remove_int(avl, 993); - avl = gpr_avl_add(avl, box(888), box(1535)); + avl = gpr_avl_add(avl, box(888), box(1535), NULL); avl = remove_int(avl, 242); - avl = gpr_avl_add(avl, box(941), box(1537)); + avl = gpr_avl_add(avl, box(941), box(1537), NULL); avl = remove_int(avl, 415); - avl = gpr_avl_add(avl, box(992), box(1539)); + avl = gpr_avl_add(avl, box(992), box(1539), NULL); avl = remove_int(avl, 289); - avl = gpr_avl_add(avl, box(60), box(1541)); - avl = gpr_avl_add(avl, box(97), box(1542)); + avl = gpr_avl_add(avl, box(60), box(1541), NULL); + avl = gpr_avl_add(avl, box(97), box(1542), NULL); avl = remove_int(avl, 965); avl = remove_int(avl, 267); avl = remove_int(avl, 360); - avl = gpr_avl_add(avl, box(5), box(1546)); + avl = gpr_avl_add(avl, box(5), box(1546), NULL); avl = remove_int(avl, 429); - avl = gpr_avl_add(avl, box(412), box(1548)); + avl = gpr_avl_add(avl, box(412), box(1548), NULL); avl = remove_int(avl, 632); avl = remove_int(avl, 113); - avl = gpr_avl_add(avl, box(48), box(1551)); - avl = gpr_avl_add(avl, box(108), box(1552)); - avl = gpr_avl_add(avl, box(750), box(1553)); + avl = gpr_avl_add(avl, box(48), box(1551), NULL); + avl = gpr_avl_add(avl, box(108), box(1552), NULL); + avl = gpr_avl_add(avl, box(750), box(1553), NULL); avl = remove_int(avl, 188); - avl = gpr_avl_add(avl, box(668), box(1555)); + avl = gpr_avl_add(avl, box(668), box(1555), NULL); avl = remove_int(avl, 37); avl = remove_int(avl, 737); - avl = gpr_avl_add(avl, box(93), box(1558)); - avl = gpr_avl_add(avl, box(628), box(1559)); - avl = gpr_avl_add(avl, box(480), box(1560)); + avl = gpr_avl_add(avl, box(93), box(1558), NULL); + avl = gpr_avl_add(avl, box(628), box(1559), NULL); + avl = gpr_avl_add(avl, box(480), box(1560), NULL); avl = remove_int(avl, 958); avl = remove_int(avl, 565); avl = remove_int(avl, 32); avl = remove_int(avl, 1); avl = remove_int(avl, 335); - avl = gpr_avl_add(avl, box(136), box(1566)); - avl = gpr_avl_add(avl, box(469), box(1567)); + avl = gpr_avl_add(avl, box(136), box(1566), NULL); + avl = gpr_avl_add(avl, box(469), box(1567), NULL); avl = remove_int(avl, 349); - avl = gpr_avl_add(avl, box(768), box(1569)); - avl = gpr_avl_add(avl, box(915), box(1570)); + avl = gpr_avl_add(avl, box(768), box(1569), NULL); + avl = gpr_avl_add(avl, box(915), box(1570), NULL); avl = remove_int(avl, 1014); - avl = gpr_avl_add(avl, box(117), box(1572)); + avl = gpr_avl_add(avl, box(117), box(1572), NULL); avl = remove_int(avl, 62); - avl = gpr_avl_add(avl, box(382), box(1574)); + avl = gpr_avl_add(avl, box(382), box(1574), NULL); avl = remove_int(avl, 571); - avl = gpr_avl_add(avl, box(655), box(1576)); - avl = gpr_avl_add(avl, box(323), box(1577)); + avl = gpr_avl_add(avl, box(655), box(1576), NULL); + avl = gpr_avl_add(avl, box(323), box(1577), NULL); avl = remove_int(avl, 869); avl = remove_int(avl, 151); - avl = gpr_avl_add(avl, box(1019), box(1580)); - avl = gpr_avl_add(avl, box(984), box(1581)); - avl = gpr_avl_add(avl, box(870), box(1582)); - avl = gpr_avl_add(avl, box(376), box(1583)); + avl = gpr_avl_add(avl, box(1019), box(1580), NULL); + avl = gpr_avl_add(avl, box(984), box(1581), NULL); + avl = gpr_avl_add(avl, box(870), box(1582), NULL); + avl = gpr_avl_add(avl, box(376), box(1583), NULL); avl = remove_int(avl, 625); - avl = gpr_avl_add(avl, box(733), box(1585)); + avl = gpr_avl_add(avl, box(733), box(1585), NULL); avl = remove_int(avl, 532); avl = remove_int(avl, 444); - avl = gpr_avl_add(avl, box(428), box(1588)); - avl = gpr_avl_add(avl, box(860), box(1589)); - avl = gpr_avl_add(avl, box(173), box(1590)); + avl = gpr_avl_add(avl, box(428), box(1588), NULL); + avl = gpr_avl_add(avl, box(860), box(1589), NULL); + avl = gpr_avl_add(avl, box(173), box(1590), NULL); avl = remove_int(avl, 649); avl = remove_int(avl, 913); avl = remove_int(avl, 1); avl = remove_int(avl, 304); - avl = gpr_avl_add(avl, box(604), box(1595)); - avl = gpr_avl_add(avl, box(639), box(1596)); + avl = gpr_avl_add(avl, box(604), box(1595), NULL); + avl = gpr_avl_add(avl, box(639), box(1596), NULL); avl = remove_int(avl, 431); - avl = gpr_avl_add(avl, box(993), box(1598)); + avl = gpr_avl_add(avl, box(993), box(1598), NULL); avl = remove_int(avl, 681); avl = remove_int(avl, 927); - avl = gpr_avl_add(avl, box(87), box(1601)); - avl = gpr_avl_add(avl, box(91), box(1602)); + avl = gpr_avl_add(avl, box(87), box(1601), NULL); + avl = gpr_avl_add(avl, box(91), box(1602), NULL); avl = remove_int(avl, 61); avl = remove_int(avl, 14); avl = remove_int(avl, 305); avl = remove_int(avl, 304); avl = remove_int(avl, 1016); - avl = gpr_avl_add(avl, box(903), box(1608)); - avl = gpr_avl_add(avl, box(951), box(1609)); - avl = gpr_avl_add(avl, box(146), box(1610)); - avl = gpr_avl_add(avl, box(482), box(1611)); - avl = gpr_avl_add(avl, box(71), box(1612)); + avl = gpr_avl_add(avl, box(903), box(1608), NULL); + avl = gpr_avl_add(avl, box(951), box(1609), NULL); + avl = gpr_avl_add(avl, box(146), box(1610), NULL); + avl = gpr_avl_add(avl, box(482), box(1611), NULL); + avl = gpr_avl_add(avl, box(71), box(1612), NULL); avl = remove_int(avl, 246); avl = remove_int(avl, 696); - avl = gpr_avl_add(avl, box(636), box(1615)); - avl = gpr_avl_add(avl, box(295), box(1616)); + avl = gpr_avl_add(avl, box(636), box(1615), NULL); + avl = gpr_avl_add(avl, box(295), box(1616), NULL); avl = remove_int(avl, 11); avl = remove_int(avl, 231); - avl = gpr_avl_add(avl, box(905), box(1619)); - avl = gpr_avl_add(avl, box(993), box(1620)); - avl = gpr_avl_add(avl, box(433), box(1621)); - avl = gpr_avl_add(avl, box(117), box(1622)); - avl = gpr_avl_add(avl, box(467), box(1623)); + avl = gpr_avl_add(avl, box(905), box(1619), NULL); + avl = gpr_avl_add(avl, box(993), box(1620), NULL); + avl = gpr_avl_add(avl, box(433), box(1621), NULL); + avl = gpr_avl_add(avl, box(117), box(1622), NULL); + avl = gpr_avl_add(avl, box(467), box(1623), NULL); avl = remove_int(avl, 419); - avl = gpr_avl_add(avl, box(179), box(1625)); + avl = gpr_avl_add(avl, box(179), box(1625), NULL); avl = remove_int(avl, 926); avl = remove_int(avl, 326); - avl = gpr_avl_add(avl, box(551), box(1628)); + avl = gpr_avl_add(avl, box(551), box(1628), NULL); avl = remove_int(avl, 14); avl = remove_int(avl, 476); avl = remove_int(avl, 823); - avl = gpr_avl_add(avl, box(350), box(1632)); - avl = gpr_avl_add(avl, box(133), box(1633)); + avl = gpr_avl_add(avl, box(350), box(1632), NULL); + avl = gpr_avl_add(avl, box(133), box(1633), NULL); avl = remove_int(avl, 906); - avl = gpr_avl_add(avl, box(827), box(1635)); - avl = gpr_avl_add(avl, box(201), box(1636)); + avl = gpr_avl_add(avl, box(827), box(1635), NULL); + avl = gpr_avl_add(avl, box(201), box(1636), NULL); avl = remove_int(avl, 124); avl = remove_int(avl, 662); - avl = gpr_avl_add(avl, box(314), box(1639)); - avl = gpr_avl_add(avl, box(986), box(1640)); - avl = gpr_avl_add(avl, box(622), box(1641)); + avl = gpr_avl_add(avl, box(314), box(1639), NULL); + avl = gpr_avl_add(avl, box(986), box(1640), NULL); + avl = gpr_avl_add(avl, box(622), box(1641), NULL); avl = remove_int(avl, 130); - avl = gpr_avl_add(avl, box(861), box(1643)); + avl = gpr_avl_add(avl, box(861), box(1643), NULL); avl = remove_int(avl, 497); avl = remove_int(avl, 905); - avl = gpr_avl_add(avl, box(502), box(1646)); + avl = gpr_avl_add(avl, box(502), box(1646), NULL); avl = remove_int(avl, 721); - avl = gpr_avl_add(avl, box(514), box(1648)); - avl = gpr_avl_add(avl, box(410), box(1649)); + avl = gpr_avl_add(avl, box(514), box(1648), NULL); + avl = gpr_avl_add(avl, box(410), box(1649), NULL); avl = remove_int(avl, 869); avl = remove_int(avl, 247); - avl = gpr_avl_add(avl, box(450), box(1652)); + avl = gpr_avl_add(avl, box(450), box(1652), NULL); avl = remove_int(avl, 364); - avl = gpr_avl_add(avl, box(963), box(1654)); - avl = gpr_avl_add(avl, box(146), box(1655)); + avl = gpr_avl_add(avl, box(963), box(1654), NULL); + avl = gpr_avl_add(avl, box(146), box(1655), NULL); avl = remove_int(avl, 147); avl = remove_int(avl, 789); - avl = gpr_avl_add(avl, box(693), box(1658)); - avl = gpr_avl_add(avl, box(959), box(1659)); + avl = gpr_avl_add(avl, box(693), box(1658), NULL); + avl = gpr_avl_add(avl, box(959), box(1659), NULL); avl = remove_int(avl, 478); - avl = gpr_avl_add(avl, box(116), box(1661)); - avl = gpr_avl_add(avl, box(520), box(1662)); - avl = gpr_avl_add(avl, box(809), box(1663)); - avl = gpr_avl_add(avl, box(667), box(1664)); - avl = gpr_avl_add(avl, box(406), box(1665)); + avl = gpr_avl_add(avl, box(116), box(1661), NULL); + avl = gpr_avl_add(avl, box(520), box(1662), NULL); + avl = gpr_avl_add(avl, box(809), box(1663), NULL); + avl = gpr_avl_add(avl, box(667), box(1664), NULL); + avl = gpr_avl_add(avl, box(406), box(1665), NULL); avl = remove_int(avl, 409); - avl = gpr_avl_add(avl, box(558), box(1667)); - avl = gpr_avl_add(avl, box(0), box(1668)); - avl = gpr_avl_add(avl, box(948), box(1669)); - avl = gpr_avl_add(avl, box(576), box(1670)); + avl = gpr_avl_add(avl, box(558), box(1667), NULL); + avl = gpr_avl_add(avl, box(0), box(1668), NULL); + avl = gpr_avl_add(avl, box(948), box(1669), NULL); + avl = gpr_avl_add(avl, box(576), box(1670), NULL); avl = remove_int(avl, 864); avl = remove_int(avl, 840); avl = remove_int(avl, 1001); - avl = gpr_avl_add(avl, box(232), box(1674)); + avl = gpr_avl_add(avl, box(232), box(1674), NULL); avl = remove_int(avl, 676); avl = remove_int(avl, 752); avl = remove_int(avl, 667); avl = remove_int(avl, 605); - avl = gpr_avl_add(avl, box(258), box(1679)); - avl = gpr_avl_add(avl, box(648), box(1680)); - avl = gpr_avl_add(avl, box(761), box(1681)); + avl = gpr_avl_add(avl, box(258), box(1679), NULL); + avl = gpr_avl_add(avl, box(648), box(1680), NULL); + avl = gpr_avl_add(avl, box(761), box(1681), NULL); avl = remove_int(avl, 293); avl = remove_int(avl, 893); - avl = gpr_avl_add(avl, box(194), box(1684)); + avl = gpr_avl_add(avl, box(194), box(1684), NULL); avl = remove_int(avl, 233); - avl = gpr_avl_add(avl, box(888), box(1686)); + avl = gpr_avl_add(avl, box(888), box(1686), NULL); avl = remove_int(avl, 470); avl = remove_int(avl, 703); avl = remove_int(avl, 190); avl = remove_int(avl, 359); - avl = gpr_avl_add(avl, box(621), box(1691)); + avl = gpr_avl_add(avl, box(621), box(1691), NULL); avl = remove_int(avl, 634); avl = remove_int(avl, 335); - avl = gpr_avl_add(avl, box(718), box(1694)); - avl = gpr_avl_add(avl, box(463), box(1695)); - avl = gpr_avl_add(avl, box(233), box(1696)); + avl = gpr_avl_add(avl, box(718), box(1694), NULL); + avl = gpr_avl_add(avl, box(463), box(1695), NULL); + avl = gpr_avl_add(avl, box(233), box(1696), NULL); avl = remove_int(avl, 376); avl = remove_int(avl, 496); avl = remove_int(avl, 819); avl = remove_int(avl, 38); avl = remove_int(avl, 436); avl = remove_int(avl, 102); - avl = gpr_avl_add(avl, box(607), box(1703)); + avl = gpr_avl_add(avl, box(607), box(1703), NULL); avl = remove_int(avl, 329); - avl = gpr_avl_add(avl, box(716), box(1705)); + avl = gpr_avl_add(avl, box(716), box(1705), NULL); avl = remove_int(avl, 639); avl = remove_int(avl, 775); avl = remove_int(avl, 578); @@ -2849,402 +2851,402 @@ static void test_badcase3(void) { avl = remove_int(avl, 679); avl = remove_int(avl, 615); avl = remove_int(avl, 104); - avl = gpr_avl_add(avl, box(414), box(1713)); - avl = gpr_avl_add(avl, box(212), box(1714)); - avl = gpr_avl_add(avl, box(266), box(1715)); - avl = gpr_avl_add(avl, box(238), box(1716)); + avl = gpr_avl_add(avl, box(414), box(1713), NULL); + avl = gpr_avl_add(avl, box(212), box(1714), NULL); + avl = gpr_avl_add(avl, box(266), box(1715), NULL); + avl = gpr_avl_add(avl, box(238), box(1716), NULL); avl = remove_int(avl, 153); - avl = gpr_avl_add(avl, box(585), box(1718)); + avl = gpr_avl_add(avl, box(585), box(1718), NULL); avl = remove_int(avl, 121); - avl = gpr_avl_add(avl, box(534), box(1720)); + avl = gpr_avl_add(avl, box(534), box(1720), NULL); avl = remove_int(avl, 579); - avl = gpr_avl_add(avl, box(127), box(1722)); - avl = gpr_avl_add(avl, box(399), box(1723)); + avl = gpr_avl_add(avl, box(127), box(1722), NULL); + avl = gpr_avl_add(avl, box(399), box(1723), NULL); avl = remove_int(avl, 417); - avl = gpr_avl_add(avl, box(978), box(1725)); - avl = gpr_avl_add(avl, box(768), box(1726)); + avl = gpr_avl_add(avl, box(978), box(1725), NULL); + avl = gpr_avl_add(avl, box(768), box(1726), NULL); avl = remove_int(avl, 985); - avl = gpr_avl_add(avl, box(536), box(1728)); - avl = gpr_avl_add(avl, box(449), box(1729)); - avl = gpr_avl_add(avl, box(586), box(1730)); + avl = gpr_avl_add(avl, box(536), box(1728), NULL); + avl = gpr_avl_add(avl, box(449), box(1729), NULL); + avl = gpr_avl_add(avl, box(586), box(1730), NULL); avl = remove_int(avl, 998); avl = remove_int(avl, 394); avl = remove_int(avl, 141); - avl = gpr_avl_add(avl, box(889), box(1734)); - avl = gpr_avl_add(avl, box(871), box(1735)); - avl = gpr_avl_add(avl, box(76), box(1736)); - avl = gpr_avl_add(avl, box(549), box(1737)); - avl = gpr_avl_add(avl, box(757), box(1738)); + avl = gpr_avl_add(avl, box(889), box(1734), NULL); + avl = gpr_avl_add(avl, box(871), box(1735), NULL); + avl = gpr_avl_add(avl, box(76), box(1736), NULL); + avl = gpr_avl_add(avl, box(549), box(1737), NULL); + avl = gpr_avl_add(avl, box(757), box(1738), NULL); avl = remove_int(avl, 908); - avl = gpr_avl_add(avl, box(789), box(1740)); + avl = gpr_avl_add(avl, box(789), box(1740), NULL); avl = remove_int(avl, 224); - avl = gpr_avl_add(avl, box(407), box(1742)); - avl = gpr_avl_add(avl, box(381), box(1743)); - avl = gpr_avl_add(avl, box(561), box(1744)); - avl = gpr_avl_add(avl, box(667), box(1745)); - avl = gpr_avl_add(avl, box(522), box(1746)); - avl = gpr_avl_add(avl, box(948), box(1747)); + avl = gpr_avl_add(avl, box(407), box(1742), NULL); + avl = gpr_avl_add(avl, box(381), box(1743), NULL); + avl = gpr_avl_add(avl, box(561), box(1744), NULL); + avl = gpr_avl_add(avl, box(667), box(1745), NULL); + avl = gpr_avl_add(avl, box(522), box(1746), NULL); + avl = gpr_avl_add(avl, box(948), box(1747), NULL); avl = remove_int(avl, 770); - avl = gpr_avl_add(avl, box(872), box(1749)); - avl = gpr_avl_add(avl, box(327), box(1750)); + avl = gpr_avl_add(avl, box(872), box(1749), NULL); + avl = gpr_avl_add(avl, box(327), box(1750), NULL); avl = remove_int(avl, 10); - avl = gpr_avl_add(avl, box(122), box(1752)); + avl = gpr_avl_add(avl, box(122), box(1752), NULL); avl = remove_int(avl, 606); - avl = gpr_avl_add(avl, box(485), box(1754)); + avl = gpr_avl_add(avl, box(485), box(1754), NULL); avl = remove_int(avl, 6); - avl = gpr_avl_add(avl, box(329), box(1756)); - avl = gpr_avl_add(avl, box(783), box(1757)); + avl = gpr_avl_add(avl, box(329), box(1756), NULL); + avl = gpr_avl_add(avl, box(783), box(1757), NULL); avl = remove_int(avl, 416); - avl = gpr_avl_add(avl, box(656), box(1759)); - avl = gpr_avl_add(avl, box(971), box(1760)); - avl = gpr_avl_add(avl, box(77), box(1761)); - avl = gpr_avl_add(avl, box(942), box(1762)); + avl = gpr_avl_add(avl, box(656), box(1759), NULL); + avl = gpr_avl_add(avl, box(971), box(1760), NULL); + avl = gpr_avl_add(avl, box(77), box(1761), NULL); + avl = gpr_avl_add(avl, box(942), box(1762), NULL); avl = remove_int(avl, 361); - avl = gpr_avl_add(avl, box(66), box(1764)); - avl = gpr_avl_add(avl, box(299), box(1765)); - avl = gpr_avl_add(avl, box(929), box(1766)); - avl = gpr_avl_add(avl, box(797), box(1767)); + avl = gpr_avl_add(avl, box(66), box(1764), NULL); + avl = gpr_avl_add(avl, box(299), box(1765), NULL); + avl = gpr_avl_add(avl, box(929), box(1766), NULL); + avl = gpr_avl_add(avl, box(797), box(1767), NULL); avl = remove_int(avl, 869); avl = remove_int(avl, 907); - avl = gpr_avl_add(avl, box(870), box(1770)); + avl = gpr_avl_add(avl, box(870), box(1770), NULL); avl = remove_int(avl, 580); avl = remove_int(avl, 120); - avl = gpr_avl_add(avl, box(913), box(1773)); + avl = gpr_avl_add(avl, box(913), box(1773), NULL); avl = remove_int(avl, 480); - avl = gpr_avl_add(avl, box(489), box(1775)); + avl = gpr_avl_add(avl, box(489), box(1775), NULL); avl = remove_int(avl, 845); - avl = gpr_avl_add(avl, box(896), box(1777)); + avl = gpr_avl_add(avl, box(896), box(1777), NULL); avl = remove_int(avl, 567); avl = remove_int(avl, 427); - avl = gpr_avl_add(avl, box(443), box(1780)); - avl = gpr_avl_add(avl, box(3), box(1781)); + avl = gpr_avl_add(avl, box(443), box(1780), NULL); + avl = gpr_avl_add(avl, box(3), box(1781), NULL); avl = remove_int(avl, 12); - avl = gpr_avl_add(avl, box(376), box(1783)); - avl = gpr_avl_add(avl, box(155), box(1784)); - avl = gpr_avl_add(avl, box(188), box(1785)); - avl = gpr_avl_add(avl, box(149), box(1786)); - avl = gpr_avl_add(avl, box(178), box(1787)); + avl = gpr_avl_add(avl, box(376), box(1783), NULL); + avl = gpr_avl_add(avl, box(155), box(1784), NULL); + avl = gpr_avl_add(avl, box(188), box(1785), NULL); + avl = gpr_avl_add(avl, box(149), box(1786), NULL); + avl = gpr_avl_add(avl, box(178), box(1787), NULL); avl = remove_int(avl, 84); - avl = gpr_avl_add(avl, box(805), box(1789)); - avl = gpr_avl_add(avl, box(612), box(1790)); + avl = gpr_avl_add(avl, box(805), box(1789), NULL); + avl = gpr_avl_add(avl, box(612), box(1790), NULL); avl = remove_int(avl, 991); - avl = gpr_avl_add(avl, box(837), box(1792)); + avl = gpr_avl_add(avl, box(837), box(1792), NULL); avl = remove_int(avl, 173); avl = remove_int(avl, 72); - avl = gpr_avl_add(avl, box(1014), box(1795)); + avl = gpr_avl_add(avl, box(1014), box(1795), NULL); avl = remove_int(avl, 303); - avl = gpr_avl_add(avl, box(865), box(1797)); - avl = gpr_avl_add(avl, box(793), box(1798)); + avl = gpr_avl_add(avl, box(865), box(1797), NULL); + avl = gpr_avl_add(avl, box(793), box(1798), NULL); avl = remove_int(avl, 173); avl = remove_int(avl, 477); - avl = gpr_avl_add(avl, box(950), box(1801)); - avl = gpr_avl_add(avl, box(105), box(1802)); - avl = gpr_avl_add(avl, box(895), box(1803)); - avl = gpr_avl_add(avl, box(171), box(1804)); - avl = gpr_avl_add(avl, box(753), box(1805)); - avl = gpr_avl_add(avl, box(946), box(1806)); + avl = gpr_avl_add(avl, box(950), box(1801), NULL); + avl = gpr_avl_add(avl, box(105), box(1802), NULL); + avl = gpr_avl_add(avl, box(895), box(1803), NULL); + avl = gpr_avl_add(avl, box(171), box(1804), NULL); + avl = gpr_avl_add(avl, box(753), box(1805), NULL); + avl = gpr_avl_add(avl, box(946), box(1806), NULL); avl = remove_int(avl, 194); avl = remove_int(avl, 559); avl = remove_int(avl, 116); - avl = gpr_avl_add(avl, box(968), box(1810)); + avl = gpr_avl_add(avl, box(968), box(1810), NULL); avl = remove_int(avl, 124); avl = remove_int(avl, 99); - avl = gpr_avl_add(avl, box(563), box(1813)); + avl = gpr_avl_add(avl, box(563), box(1813), NULL); avl = remove_int(avl, 182); - avl = gpr_avl_add(avl, box(816), box(1815)); + avl = gpr_avl_add(avl, box(816), box(1815), NULL); avl = remove_int(avl, 73); avl = remove_int(avl, 261); - avl = gpr_avl_add(avl, box(847), box(1818)); - avl = gpr_avl_add(avl, box(368), box(1819)); - avl = gpr_avl_add(avl, box(808), box(1820)); - avl = gpr_avl_add(avl, box(779), box(1821)); + avl = gpr_avl_add(avl, box(847), box(1818), NULL); + avl = gpr_avl_add(avl, box(368), box(1819), NULL); + avl = gpr_avl_add(avl, box(808), box(1820), NULL); + avl = gpr_avl_add(avl, box(779), box(1821), NULL); avl = remove_int(avl, 818); - avl = gpr_avl_add(avl, box(466), box(1823)); + avl = gpr_avl_add(avl, box(466), box(1823), NULL); avl = remove_int(avl, 316); - avl = gpr_avl_add(avl, box(986), box(1825)); - avl = gpr_avl_add(avl, box(688), box(1826)); - avl = gpr_avl_add(avl, box(509), box(1827)); - avl = gpr_avl_add(avl, box(51), box(1828)); + avl = gpr_avl_add(avl, box(986), box(1825), NULL); + avl = gpr_avl_add(avl, box(688), box(1826), NULL); + avl = gpr_avl_add(avl, box(509), box(1827), NULL); + avl = gpr_avl_add(avl, box(51), box(1828), NULL); avl = remove_int(avl, 655); avl = remove_int(avl, 785); avl = remove_int(avl, 893); - avl = gpr_avl_add(avl, box(167), box(1832)); + avl = gpr_avl_add(avl, box(167), box(1832), NULL); avl = remove_int(avl, 13); avl = remove_int(avl, 263); - avl = gpr_avl_add(avl, box(1009), box(1835)); + avl = gpr_avl_add(avl, box(1009), box(1835), NULL); avl = remove_int(avl, 480); avl = remove_int(avl, 778); avl = remove_int(avl, 713); avl = remove_int(avl, 628); - avl = gpr_avl_add(avl, box(803), box(1840)); + avl = gpr_avl_add(avl, box(803), box(1840), NULL); avl = remove_int(avl, 267); - avl = gpr_avl_add(avl, box(676), box(1842)); - avl = gpr_avl_add(avl, box(231), box(1843)); - avl = gpr_avl_add(avl, box(824), box(1844)); + avl = gpr_avl_add(avl, box(676), box(1842), NULL); + avl = gpr_avl_add(avl, box(231), box(1843), NULL); + avl = gpr_avl_add(avl, box(824), box(1844), NULL); avl = remove_int(avl, 961); - avl = gpr_avl_add(avl, box(311), box(1846)); - avl = gpr_avl_add(avl, box(420), box(1847)); - avl = gpr_avl_add(avl, box(960), box(1848)); - avl = gpr_avl_add(avl, box(468), box(1849)); - avl = gpr_avl_add(avl, box(815), box(1850)); + avl = gpr_avl_add(avl, box(311), box(1846), NULL); + avl = gpr_avl_add(avl, box(420), box(1847), NULL); + avl = gpr_avl_add(avl, box(960), box(1848), NULL); + avl = gpr_avl_add(avl, box(468), box(1849), NULL); + avl = gpr_avl_add(avl, box(815), box(1850), NULL); avl = remove_int(avl, 247); avl = remove_int(avl, 194); - avl = gpr_avl_add(avl, box(546), box(1853)); + avl = gpr_avl_add(avl, box(546), box(1853), NULL); avl = remove_int(avl, 222); avl = remove_int(avl, 914); avl = remove_int(avl, 741); - avl = gpr_avl_add(avl, box(470), box(1857)); - avl = gpr_avl_add(avl, box(933), box(1858)); - avl = gpr_avl_add(avl, box(97), box(1859)); + avl = gpr_avl_add(avl, box(470), box(1857), NULL); + avl = gpr_avl_add(avl, box(933), box(1858), NULL); + avl = gpr_avl_add(avl, box(97), box(1859), NULL); avl = remove_int(avl, 564); avl = remove_int(avl, 295); - avl = gpr_avl_add(avl, box(864), box(1862)); + avl = gpr_avl_add(avl, box(864), box(1862), NULL); avl = remove_int(avl, 329); - avl = gpr_avl_add(avl, box(124), box(1864)); - avl = gpr_avl_add(avl, box(1000), box(1865)); - avl = gpr_avl_add(avl, box(228), box(1866)); - avl = gpr_avl_add(avl, box(187), box(1867)); + avl = gpr_avl_add(avl, box(124), box(1864), NULL); + avl = gpr_avl_add(avl, box(1000), box(1865), NULL); + avl = gpr_avl_add(avl, box(228), box(1866), NULL); + avl = gpr_avl_add(avl, box(187), box(1867), NULL); avl = remove_int(avl, 224); avl = remove_int(avl, 306); avl = remove_int(avl, 884); - avl = gpr_avl_add(avl, box(449), box(1871)); - avl = gpr_avl_add(avl, box(353), box(1872)); - avl = gpr_avl_add(avl, box(994), box(1873)); - avl = gpr_avl_add(avl, box(596), box(1874)); - avl = gpr_avl_add(avl, box(996), box(1875)); - avl = gpr_avl_add(avl, box(101), box(1876)); - avl = gpr_avl_add(avl, box(1012), box(1877)); - avl = gpr_avl_add(avl, box(982), box(1878)); - avl = gpr_avl_add(avl, box(742), box(1879)); + avl = gpr_avl_add(avl, box(449), box(1871), NULL); + avl = gpr_avl_add(avl, box(353), box(1872), NULL); + avl = gpr_avl_add(avl, box(994), box(1873), NULL); + avl = gpr_avl_add(avl, box(596), box(1874), NULL); + avl = gpr_avl_add(avl, box(996), box(1875), NULL); + avl = gpr_avl_add(avl, box(101), box(1876), NULL); + avl = gpr_avl_add(avl, box(1012), box(1877), NULL); + avl = gpr_avl_add(avl, box(982), box(1878), NULL); + avl = gpr_avl_add(avl, box(742), box(1879), NULL); avl = remove_int(avl, 92); avl = remove_int(avl, 1022); - avl = gpr_avl_add(avl, box(941), box(1882)); + avl = gpr_avl_add(avl, box(941), box(1882), NULL); avl = remove_int(avl, 742); avl = remove_int(avl, 919); - avl = gpr_avl_add(avl, box(588), box(1885)); + avl = gpr_avl_add(avl, box(588), box(1885), NULL); avl = remove_int(avl, 221); - avl = gpr_avl_add(avl, box(356), box(1887)); - avl = gpr_avl_add(avl, box(932), box(1888)); + avl = gpr_avl_add(avl, box(356), box(1887), NULL); + avl = gpr_avl_add(avl, box(932), box(1888), NULL); avl = remove_int(avl, 837); - avl = gpr_avl_add(avl, box(394), box(1890)); - avl = gpr_avl_add(avl, box(642), box(1891)); - avl = gpr_avl_add(avl, box(52), box(1892)); - avl = gpr_avl_add(avl, box(437), box(1893)); - avl = gpr_avl_add(avl, box(948), box(1894)); - avl = gpr_avl_add(avl, box(93), box(1895)); + avl = gpr_avl_add(avl, box(394), box(1890), NULL); + avl = gpr_avl_add(avl, box(642), box(1891), NULL); + avl = gpr_avl_add(avl, box(52), box(1892), NULL); + avl = gpr_avl_add(avl, box(437), box(1893), NULL); + avl = gpr_avl_add(avl, box(948), box(1894), NULL); + avl = gpr_avl_add(avl, box(93), box(1895), NULL); avl = remove_int(avl, 873); avl = remove_int(avl, 336); avl = remove_int(avl, 277); avl = remove_int(avl, 932); - avl = gpr_avl_add(avl, box(80), box(1900)); - avl = gpr_avl_add(avl, box(952), box(1901)); - avl = gpr_avl_add(avl, box(510), box(1902)); + avl = gpr_avl_add(avl, box(80), box(1900), NULL); + avl = gpr_avl_add(avl, box(952), box(1901), NULL); + avl = gpr_avl_add(avl, box(510), box(1902), NULL); avl = remove_int(avl, 876); avl = remove_int(avl, 612); - avl = gpr_avl_add(avl, box(923), box(1905)); - avl = gpr_avl_add(avl, box(475), box(1906)); + avl = gpr_avl_add(avl, box(923), box(1905), NULL); + avl = gpr_avl_add(avl, box(475), box(1906), NULL); avl = remove_int(avl, 478); avl = remove_int(avl, 148); - avl = gpr_avl_add(avl, box(538), box(1909)); + avl = gpr_avl_add(avl, box(538), box(1909), NULL); avl = remove_int(avl, 47); - avl = gpr_avl_add(avl, box(89), box(1911)); + avl = gpr_avl_add(avl, box(89), box(1911), NULL); avl = remove_int(avl, 723); - avl = gpr_avl_add(avl, box(687), box(1913)); - avl = gpr_avl_add(avl, box(480), box(1914)); - avl = gpr_avl_add(avl, box(149), box(1915)); + avl = gpr_avl_add(avl, box(687), box(1913), NULL); + avl = gpr_avl_add(avl, box(480), box(1914), NULL); + avl = gpr_avl_add(avl, box(149), box(1915), NULL); avl = remove_int(avl, 68); avl = remove_int(avl, 862); avl = remove_int(avl, 363); - avl = gpr_avl_add(avl, box(996), box(1919)); + avl = gpr_avl_add(avl, box(996), box(1919), NULL); avl = remove_int(avl, 380); - avl = gpr_avl_add(avl, box(957), box(1921)); + avl = gpr_avl_add(avl, box(957), box(1921), NULL); avl = remove_int(avl, 413); - avl = gpr_avl_add(avl, box(360), box(1923)); - avl = gpr_avl_add(avl, box(304), box(1924)); - avl = gpr_avl_add(avl, box(634), box(1925)); - avl = gpr_avl_add(avl, box(506), box(1926)); + avl = gpr_avl_add(avl, box(360), box(1923), NULL); + avl = gpr_avl_add(avl, box(304), box(1924), NULL); + avl = gpr_avl_add(avl, box(634), box(1925), NULL); + avl = gpr_avl_add(avl, box(506), box(1926), NULL); avl = remove_int(avl, 248); - avl = gpr_avl_add(avl, box(124), box(1928)); - avl = gpr_avl_add(avl, box(181), box(1929)); + avl = gpr_avl_add(avl, box(124), box(1928), NULL); + avl = gpr_avl_add(avl, box(181), box(1929), NULL); avl = remove_int(avl, 507); - avl = gpr_avl_add(avl, box(141), box(1931)); + avl = gpr_avl_add(avl, box(141), box(1931), NULL); avl = remove_int(avl, 409); avl = remove_int(avl, 129); avl = remove_int(avl, 694); avl = remove_int(avl, 723); - avl = gpr_avl_add(avl, box(998), box(1936)); - avl = gpr_avl_add(avl, box(906), box(1937)); - avl = gpr_avl_add(avl, box(44), box(1938)); + avl = gpr_avl_add(avl, box(998), box(1936), NULL); + avl = gpr_avl_add(avl, box(906), box(1937), NULL); + avl = gpr_avl_add(avl, box(44), box(1938), NULL); avl = remove_int(avl, 949); avl = remove_int(avl, 117); - avl = gpr_avl_add(avl, box(700), box(1941)); - avl = gpr_avl_add(avl, box(258), box(1942)); + avl = gpr_avl_add(avl, box(700), box(1941), NULL); + avl = gpr_avl_add(avl, box(258), box(1942), NULL); avl = remove_int(avl, 828); - avl = gpr_avl_add(avl, box(860), box(1944)); - avl = gpr_avl_add(avl, box(987), box(1945)); - avl = gpr_avl_add(avl, box(316), box(1946)); - avl = gpr_avl_add(avl, box(919), box(1947)); + avl = gpr_avl_add(avl, box(860), box(1944), NULL); + avl = gpr_avl_add(avl, box(987), box(1945), NULL); + avl = gpr_avl_add(avl, box(316), box(1946), NULL); + avl = gpr_avl_add(avl, box(919), box(1947), NULL); avl = remove_int(avl, 84); - avl = gpr_avl_add(avl, box(473), box(1949)); + avl = gpr_avl_add(avl, box(473), box(1949), NULL); avl = remove_int(avl, 127); avl = remove_int(avl, 829); avl = remove_int(avl, 829); - avl = gpr_avl_add(avl, box(488), box(1953)); - avl = gpr_avl_add(avl, box(954), box(1954)); + avl = gpr_avl_add(avl, box(488), box(1953), NULL); + avl = gpr_avl_add(avl, box(954), box(1954), NULL); avl = remove_int(avl, 198); avl = remove_int(avl, 972); avl = remove_int(avl, 670); - avl = gpr_avl_add(avl, box(822), box(1958)); + avl = gpr_avl_add(avl, box(822), box(1958), NULL); avl = remove_int(avl, 589); avl = remove_int(avl, 459); - avl = gpr_avl_add(avl, box(1003), box(1961)); - avl = gpr_avl_add(avl, box(657), box(1962)); - avl = gpr_avl_add(avl, box(477), box(1963)); - avl = gpr_avl_add(avl, box(923), box(1964)); + avl = gpr_avl_add(avl, box(1003), box(1961), NULL); + avl = gpr_avl_add(avl, box(657), box(1962), NULL); + avl = gpr_avl_add(avl, box(477), box(1963), NULL); + avl = gpr_avl_add(avl, box(923), box(1964), NULL); avl = remove_int(avl, 496); avl = remove_int(avl, 99); - avl = gpr_avl_add(avl, box(127), box(1967)); - avl = gpr_avl_add(avl, box(1013), box(1968)); - avl = gpr_avl_add(avl, box(778), box(1969)); + avl = gpr_avl_add(avl, box(127), box(1967), NULL); + avl = gpr_avl_add(avl, box(1013), box(1968), NULL); + avl = gpr_avl_add(avl, box(778), box(1969), NULL); avl = remove_int(avl, 5); avl = remove_int(avl, 990); avl = remove_int(avl, 850); avl = remove_int(avl, 160); avl = remove_int(avl, 86); - avl = gpr_avl_add(avl, box(283), box(1975)); + avl = gpr_avl_add(avl, box(283), box(1975), NULL); avl = remove_int(avl, 278); avl = remove_int(avl, 297); avl = remove_int(avl, 137); avl = remove_int(avl, 653); - avl = gpr_avl_add(avl, box(702), box(1980)); + avl = gpr_avl_add(avl, box(702), box(1980), NULL); avl = remove_int(avl, 63); avl = remove_int(avl, 427); avl = remove_int(avl, 706); avl = remove_int(avl, 806); - avl = gpr_avl_add(avl, box(335), box(1985)); - avl = gpr_avl_add(avl, box(412), box(1986)); + avl = gpr_avl_add(avl, box(335), box(1985), NULL); + avl = gpr_avl_add(avl, box(412), box(1986), NULL); avl = remove_int(avl, 766); avl = remove_int(avl, 937); avl = remove_int(avl, 886); avl = remove_int(avl, 652); - avl = gpr_avl_add(avl, box(545), box(1991)); - avl = gpr_avl_add(avl, box(408), box(1992)); - avl = gpr_avl_add(avl, box(841), box(1993)); + avl = gpr_avl_add(avl, box(545), box(1991), NULL); + avl = gpr_avl_add(avl, box(408), box(1992), NULL); + avl = gpr_avl_add(avl, box(841), box(1993), NULL); avl = remove_int(avl, 593); - avl = gpr_avl_add(avl, box(582), box(1995)); - avl = gpr_avl_add(avl, box(597), box(1996)); + avl = gpr_avl_add(avl, box(582), box(1995), NULL); + avl = gpr_avl_add(avl, box(597), box(1996), NULL); avl = remove_int(avl, 49); avl = remove_int(avl, 835); - avl = gpr_avl_add(avl, box(417), box(1999)); - avl = gpr_avl_add(avl, box(191), box(2000)); + avl = gpr_avl_add(avl, box(417), box(1999), NULL); + avl = gpr_avl_add(avl, box(191), box(2000), NULL); avl = remove_int(avl, 406); - avl = gpr_avl_add(avl, box(30), box(2002)); + avl = gpr_avl_add(avl, box(30), box(2002), NULL); avl = remove_int(avl, 841); avl = remove_int(avl, 50); - avl = gpr_avl_add(avl, box(967), box(2005)); - avl = gpr_avl_add(avl, box(849), box(2006)); + avl = gpr_avl_add(avl, box(967), box(2005), NULL); + avl = gpr_avl_add(avl, box(849), box(2006), NULL); avl = remove_int(avl, 608); - avl = gpr_avl_add(avl, box(306), box(2008)); + avl = gpr_avl_add(avl, box(306), box(2008), NULL); avl = remove_int(avl, 779); - avl = gpr_avl_add(avl, box(897), box(2010)); - avl = gpr_avl_add(avl, box(147), box(2011)); + avl = gpr_avl_add(avl, box(897), box(2010), NULL); + avl = gpr_avl_add(avl, box(147), box(2011), NULL); avl = remove_int(avl, 982); - avl = gpr_avl_add(avl, box(470), box(2013)); + avl = gpr_avl_add(avl, box(470), box(2013), NULL); avl = remove_int(avl, 951); - avl = gpr_avl_add(avl, box(388), box(2015)); + avl = gpr_avl_add(avl, box(388), box(2015), NULL); avl = remove_int(avl, 616); avl = remove_int(avl, 721); avl = remove_int(avl, 942); avl = remove_int(avl, 589); - avl = gpr_avl_add(avl, box(218), box(2020)); + avl = gpr_avl_add(avl, box(218), box(2020), NULL); avl = remove_int(avl, 671); - avl = gpr_avl_add(avl, box(1020), box(2022)); + avl = gpr_avl_add(avl, box(1020), box(2022), NULL); avl = remove_int(avl, 277); - avl = gpr_avl_add(avl, box(681), box(2024)); - avl = gpr_avl_add(avl, box(179), box(2025)); - avl = gpr_avl_add(avl, box(370), box(2026)); - avl = gpr_avl_add(avl, box(0), box(2027)); + avl = gpr_avl_add(avl, box(681), box(2024), NULL); + avl = gpr_avl_add(avl, box(179), box(2025), NULL); + avl = gpr_avl_add(avl, box(370), box(2026), NULL); + avl = gpr_avl_add(avl, box(0), box(2027), NULL); avl = remove_int(avl, 523); - avl = gpr_avl_add(avl, box(99), box(2029)); - avl = gpr_avl_add(avl, box(334), box(2030)); - avl = gpr_avl_add(avl, box(569), box(2031)); - avl = gpr_avl_add(avl, box(257), box(2032)); + avl = gpr_avl_add(avl, box(99), box(2029), NULL); + avl = gpr_avl_add(avl, box(334), box(2030), NULL); + avl = gpr_avl_add(avl, box(569), box(2031), NULL); + avl = gpr_avl_add(avl, box(257), box(2032), NULL); avl = remove_int(avl, 572); - avl = gpr_avl_add(avl, box(805), box(2034)); - avl = gpr_avl_add(avl, box(143), box(2035)); - avl = gpr_avl_add(avl, box(670), box(2036)); + avl = gpr_avl_add(avl, box(805), box(2034), NULL); + avl = gpr_avl_add(avl, box(143), box(2035), NULL); + avl = gpr_avl_add(avl, box(670), box(2036), NULL); avl = remove_int(avl, 42); - avl = gpr_avl_add(avl, box(46), box(2038)); + avl = gpr_avl_add(avl, box(46), box(2038), NULL); avl = remove_int(avl, 970); - avl = gpr_avl_add(avl, box(353), box(2040)); + avl = gpr_avl_add(avl, box(353), box(2040), NULL); avl = remove_int(avl, 258); - avl = gpr_avl_add(avl, box(451), box(2042)); - avl = gpr_avl_add(avl, box(28), box(2043)); - avl = gpr_avl_add(avl, box(729), box(2044)); - avl = gpr_avl_add(avl, box(401), box(2045)); - avl = gpr_avl_add(avl, box(614), box(2046)); + avl = gpr_avl_add(avl, box(451), box(2042), NULL); + avl = gpr_avl_add(avl, box(28), box(2043), NULL); + avl = gpr_avl_add(avl, box(729), box(2044), NULL); + avl = gpr_avl_add(avl, box(401), box(2045), NULL); + avl = gpr_avl_add(avl, box(614), box(2046), NULL); avl = remove_int(avl, 990); avl = remove_int(avl, 212); avl = remove_int(avl, 22); avl = remove_int(avl, 677); - avl = gpr_avl_add(avl, box(1016), box(2051)); - avl = gpr_avl_add(avl, box(980), box(2052)); - avl = gpr_avl_add(avl, box(990), box(2053)); - avl = gpr_avl_add(avl, box(355), box(2054)); + avl = gpr_avl_add(avl, box(1016), box(2051), NULL); + avl = gpr_avl_add(avl, box(980), box(2052), NULL); + avl = gpr_avl_add(avl, box(990), box(2053), NULL); + avl = gpr_avl_add(avl, box(355), box(2054), NULL); avl = remove_int(avl, 730); avl = remove_int(avl, 37); - avl = gpr_avl_add(avl, box(407), box(2057)); - avl = gpr_avl_add(avl, box(222), box(2058)); - avl = gpr_avl_add(avl, box(439), box(2059)); - avl = gpr_avl_add(avl, box(563), box(2060)); + avl = gpr_avl_add(avl, box(407), box(2057), NULL); + avl = gpr_avl_add(avl, box(222), box(2058), NULL); + avl = gpr_avl_add(avl, box(439), box(2059), NULL); + avl = gpr_avl_add(avl, box(563), box(2060), NULL); avl = remove_int(avl, 992); avl = remove_int(avl, 786); - avl = gpr_avl_add(avl, box(1), box(2063)); - avl = gpr_avl_add(avl, box(473), box(2064)); - avl = gpr_avl_add(avl, box(992), box(2065)); + avl = gpr_avl_add(avl, box(1), box(2063), NULL); + avl = gpr_avl_add(avl, box(473), box(2064), NULL); + avl = gpr_avl_add(avl, box(992), box(2065), NULL); avl = remove_int(avl, 190); avl = remove_int(avl, 450); avl = remove_int(avl, 1020); avl = remove_int(avl, 149); - avl = gpr_avl_add(avl, box(329), box(2070)); - avl = gpr_avl_add(avl, box(35), box(2071)); + avl = gpr_avl_add(avl, box(329), box(2070), NULL); + avl = gpr_avl_add(avl, box(35), box(2071), NULL); avl = remove_int(avl, 843); - avl = gpr_avl_add(avl, box(855), box(2073)); + avl = gpr_avl_add(avl, box(855), box(2073), NULL); avl = remove_int(avl, 878); - avl = gpr_avl_add(avl, box(993), box(2075)); - avl = gpr_avl_add(avl, box(87), box(2076)); - avl = gpr_avl_add(avl, box(572), box(2077)); + avl = gpr_avl_add(avl, box(993), box(2075), NULL); + avl = gpr_avl_add(avl, box(87), box(2076), NULL); + avl = gpr_avl_add(avl, box(572), box(2077), NULL); avl = remove_int(avl, 896); - avl = gpr_avl_add(avl, box(849), box(2079)); + avl = gpr_avl_add(avl, box(849), box(2079), NULL); avl = remove_int(avl, 597); - avl = gpr_avl_add(avl, box(472), box(2081)); + avl = gpr_avl_add(avl, box(472), box(2081), NULL); avl = remove_int(avl, 778); avl = remove_int(avl, 934); avl = remove_int(avl, 314); - avl = gpr_avl_add(avl, box(101), box(2085)); + avl = gpr_avl_add(avl, box(101), box(2085), NULL); avl = remove_int(avl, 938); avl = remove_int(avl, 1010); - avl = gpr_avl_add(avl, box(579), box(2088)); + avl = gpr_avl_add(avl, box(579), box(2088), NULL); avl = remove_int(avl, 798); avl = remove_int(avl, 88); - avl = gpr_avl_add(avl, box(851), box(2091)); + avl = gpr_avl_add(avl, box(851), box(2091), NULL); avl = remove_int(avl, 705); - avl = gpr_avl_add(avl, box(26), box(2093)); + avl = gpr_avl_add(avl, box(26), box(2093), NULL); avl = remove_int(avl, 973); - avl = gpr_avl_add(avl, box(923), box(2095)); + avl = gpr_avl_add(avl, box(923), box(2095), NULL); avl = remove_int(avl, 668); - avl = gpr_avl_add(avl, box(310), box(2097)); - avl = gpr_avl_add(avl, box(269), box(2098)); + avl = gpr_avl_add(avl, box(310), box(2097), NULL); + avl = gpr_avl_add(avl, box(269), box(2098), NULL); avl = remove_int(avl, 173); - avl = gpr_avl_add(avl, box(279), box(2100)); + avl = gpr_avl_add(avl, box(279), box(2100), NULL); avl = remove_int(avl, 203); - avl = gpr_avl_add(avl, box(411), box(2102)); + avl = gpr_avl_add(avl, box(411), box(2102), NULL); avl = remove_int(avl, 950); - avl = gpr_avl_add(avl, box(6), box(2104)); + avl = gpr_avl_add(avl, box(6), box(2104), NULL); avl = remove_int(avl, 400); avl = remove_int(avl, 468); avl = remove_int(avl, 271); - avl = gpr_avl_add(avl, box(627), box(2108)); + avl = gpr_avl_add(avl, box(627), box(2108), NULL); avl = remove_int(avl, 727); avl = remove_int(avl, 148); avl = remove_int(avl, 98); @@ -3253,259 +3255,259 @@ static void test_badcase3(void) { avl = remove_int(avl, 628); avl = remove_int(avl, 826); avl = remove_int(avl, 664); - avl = gpr_avl_add(avl, box(76), box(2117)); + avl = gpr_avl_add(avl, box(76), box(2117), NULL); avl = remove_int(avl, 194); avl = remove_int(avl, 18); - avl = gpr_avl_add(avl, box(727), box(2120)); + avl = gpr_avl_add(avl, box(727), box(2120), NULL); avl = remove_int(avl, 295); - avl = gpr_avl_add(avl, box(645), box(2122)); + avl = gpr_avl_add(avl, box(645), box(2122), NULL); avl = remove_int(avl, 321); avl = remove_int(avl, 863); - avl = gpr_avl_add(avl, box(824), box(2125)); - avl = gpr_avl_add(avl, box(651), box(2126)); - avl = gpr_avl_add(avl, box(804), box(2127)); + avl = gpr_avl_add(avl, box(824), box(2125), NULL); + avl = gpr_avl_add(avl, box(651), box(2126), NULL); + avl = gpr_avl_add(avl, box(804), box(2127), NULL); avl = remove_int(avl, 307); - avl = gpr_avl_add(avl, box(867), box(2129)); + avl = gpr_avl_add(avl, box(867), box(2129), NULL); avl = remove_int(avl, 384); - avl = gpr_avl_add(avl, box(819), box(2131)); + avl = gpr_avl_add(avl, box(819), box(2131), NULL); avl = remove_int(avl, 674); - avl = gpr_avl_add(avl, box(76), box(2133)); + avl = gpr_avl_add(avl, box(76), box(2133), NULL); avl = remove_int(avl, 898); - avl = gpr_avl_add(avl, box(45), box(2135)); - avl = gpr_avl_add(avl, box(512), box(2136)); + avl = gpr_avl_add(avl, box(45), box(2135), NULL); + avl = gpr_avl_add(avl, box(512), box(2136), NULL); avl = remove_int(avl, 773); avl = remove_int(avl, 907); avl = remove_int(avl, 382); avl = remove_int(avl, 95); avl = remove_int(avl, 734); avl = remove_int(avl, 81); - avl = gpr_avl_add(avl, box(348), box(2143)); + avl = gpr_avl_add(avl, box(348), box(2143), NULL); avl = remove_int(avl, 509); avl = remove_int(avl, 301); - avl = gpr_avl_add(avl, box(861), box(2146)); - avl = gpr_avl_add(avl, box(918), box(2147)); + avl = gpr_avl_add(avl, box(861), box(2146), NULL); + avl = gpr_avl_add(avl, box(918), box(2147), NULL); avl = remove_int(avl, 992); - avl = gpr_avl_add(avl, box(356), box(2149)); + avl = gpr_avl_add(avl, box(356), box(2149), NULL); avl = remove_int(avl, 64); avl = remove_int(avl, 444); avl = remove_int(avl, 741); - avl = gpr_avl_add(avl, box(710), box(2153)); - avl = gpr_avl_add(avl, box(264), box(2154)); + avl = gpr_avl_add(avl, box(710), box(2153), NULL); + avl = gpr_avl_add(avl, box(264), box(2154), NULL); avl = remove_int(avl, 347); avl = remove_int(avl, 250); - avl = gpr_avl_add(avl, box(82), box(2157)); - avl = gpr_avl_add(avl, box(571), box(2158)); + avl = gpr_avl_add(avl, box(82), box(2157), NULL); + avl = gpr_avl_add(avl, box(571), box(2158), NULL); avl = remove_int(avl, 721); avl = remove_int(avl, 622); - avl = gpr_avl_add(avl, box(950), box(2161)); - avl = gpr_avl_add(avl, box(94), box(2162)); + avl = gpr_avl_add(avl, box(950), box(2161), NULL); + avl = gpr_avl_add(avl, box(94), box(2162), NULL); avl = remove_int(avl, 970); - avl = gpr_avl_add(avl, box(815), box(2164)); + avl = gpr_avl_add(avl, box(815), box(2164), NULL); avl = remove_int(avl, 930); avl = remove_int(avl, 703); - avl = gpr_avl_add(avl, box(432), box(2167)); + avl = gpr_avl_add(avl, box(432), box(2167), NULL); avl = remove_int(avl, 544); - avl = gpr_avl_add(avl, box(21), box(2169)); - avl = gpr_avl_add(avl, box(186), box(2170)); + avl = gpr_avl_add(avl, box(21), box(2169), NULL); + avl = gpr_avl_add(avl, box(186), box(2170), NULL); avl = remove_int(avl, 143); - avl = gpr_avl_add(avl, box(425), box(2172)); + avl = gpr_avl_add(avl, box(425), box(2172), NULL); avl = remove_int(avl, 769); - avl = gpr_avl_add(avl, box(656), box(2174)); + avl = gpr_avl_add(avl, box(656), box(2174), NULL); avl = remove_int(avl, 29); - avl = gpr_avl_add(avl, box(464), box(2176)); + avl = gpr_avl_add(avl, box(464), box(2176), NULL); avl = remove_int(avl, 713); - avl = gpr_avl_add(avl, box(800), box(2178)); + avl = gpr_avl_add(avl, box(800), box(2178), NULL); avl = remove_int(avl, 621); - avl = gpr_avl_add(avl, box(962), box(2180)); + avl = gpr_avl_add(avl, box(962), box(2180), NULL); avl = remove_int(avl, 448); - avl = gpr_avl_add(avl, box(878), box(2182)); + avl = gpr_avl_add(avl, box(878), box(2182), NULL); avl = remove_int(avl, 39); avl = remove_int(avl, 999); - avl = gpr_avl_add(avl, box(182), box(2185)); - avl = gpr_avl_add(avl, box(429), box(2186)); - avl = gpr_avl_add(avl, box(598), box(2187)); + avl = gpr_avl_add(avl, box(182), box(2185), NULL); + avl = gpr_avl_add(avl, box(429), box(2186), NULL); + avl = gpr_avl_add(avl, box(598), box(2187), NULL); avl = remove_int(avl, 551); - avl = gpr_avl_add(avl, box(827), box(2189)); - avl = gpr_avl_add(avl, box(809), box(2190)); + avl = gpr_avl_add(avl, box(827), box(2189), NULL); + avl = gpr_avl_add(avl, box(809), box(2190), NULL); avl = remove_int(avl, 438); avl = remove_int(avl, 811); - avl = gpr_avl_add(avl, box(808), box(2193)); - avl = gpr_avl_add(avl, box(788), box(2194)); + avl = gpr_avl_add(avl, box(808), box(2193), NULL); + avl = gpr_avl_add(avl, box(788), box(2194), NULL); avl = remove_int(avl, 156); - avl = gpr_avl_add(avl, box(933), box(2196)); - avl = gpr_avl_add(avl, box(344), box(2197)); + avl = gpr_avl_add(avl, box(933), box(2196), NULL); + avl = gpr_avl_add(avl, box(344), box(2197), NULL); avl = remove_int(avl, 460); - avl = gpr_avl_add(avl, box(161), box(2199)); - avl = gpr_avl_add(avl, box(444), box(2200)); + avl = gpr_avl_add(avl, box(161), box(2199), NULL); + avl = gpr_avl_add(avl, box(444), box(2200), NULL); avl = remove_int(avl, 597); avl = remove_int(avl, 668); - avl = gpr_avl_add(avl, box(703), box(2203)); + avl = gpr_avl_add(avl, box(703), box(2203), NULL); avl = remove_int(avl, 515); - avl = gpr_avl_add(avl, box(380), box(2205)); - avl = gpr_avl_add(avl, box(338), box(2206)); + avl = gpr_avl_add(avl, box(380), box(2205), NULL); + avl = gpr_avl_add(avl, box(338), box(2206), NULL); avl = remove_int(avl, 550); avl = remove_int(avl, 946); avl = remove_int(avl, 714); avl = remove_int(avl, 739); - avl = gpr_avl_add(avl, box(413), box(2211)); + avl = gpr_avl_add(avl, box(413), box(2211), NULL); avl = remove_int(avl, 450); - avl = gpr_avl_add(avl, box(411), box(2213)); - avl = gpr_avl_add(avl, box(117), box(2214)); - avl = gpr_avl_add(avl, box(322), box(2215)); - avl = gpr_avl_add(avl, box(915), box(2216)); - avl = gpr_avl_add(avl, box(410), box(2217)); - avl = gpr_avl_add(avl, box(66), box(2218)); + avl = gpr_avl_add(avl, box(411), box(2213), NULL); + avl = gpr_avl_add(avl, box(117), box(2214), NULL); + avl = gpr_avl_add(avl, box(322), box(2215), NULL); + avl = gpr_avl_add(avl, box(915), box(2216), NULL); + avl = gpr_avl_add(avl, box(410), box(2217), NULL); + avl = gpr_avl_add(avl, box(66), box(2218), NULL); avl = remove_int(avl, 756); avl = remove_int(avl, 596); - avl = gpr_avl_add(avl, box(882), box(2221)); - avl = gpr_avl_add(avl, box(930), box(2222)); - avl = gpr_avl_add(avl, box(36), box(2223)); + avl = gpr_avl_add(avl, box(882), box(2221), NULL); + avl = gpr_avl_add(avl, box(930), box(2222), NULL); + avl = gpr_avl_add(avl, box(36), box(2223), NULL); avl = remove_int(avl, 742); - avl = gpr_avl_add(avl, box(539), box(2225)); - avl = gpr_avl_add(avl, box(596), box(2226)); + avl = gpr_avl_add(avl, box(539), box(2225), NULL); + avl = gpr_avl_add(avl, box(596), box(2226), NULL); avl = remove_int(avl, 82); avl = remove_int(avl, 686); avl = remove_int(avl, 933); avl = remove_int(avl, 42); avl = remove_int(avl, 340); - avl = gpr_avl_add(avl, box(126), box(2232)); - avl = gpr_avl_add(avl, box(493), box(2233)); - avl = gpr_avl_add(avl, box(839), box(2234)); + avl = gpr_avl_add(avl, box(126), box(2232), NULL); + avl = gpr_avl_add(avl, box(493), box(2233), NULL); + avl = gpr_avl_add(avl, box(839), box(2234), NULL); avl = remove_int(avl, 774); - avl = gpr_avl_add(avl, box(337), box(2236)); + avl = gpr_avl_add(avl, box(337), box(2236), NULL); avl = remove_int(avl, 322); - avl = gpr_avl_add(avl, box(16), box(2238)); + avl = gpr_avl_add(avl, box(16), box(2238), NULL); avl = remove_int(avl, 73); avl = remove_int(avl, 85); avl = remove_int(avl, 191); avl = remove_int(avl, 541); - avl = gpr_avl_add(avl, box(704), box(2243)); + avl = gpr_avl_add(avl, box(704), box(2243), NULL); avl = remove_int(avl, 767); avl = remove_int(avl, 1006); avl = remove_int(avl, 844); avl = remove_int(avl, 742); - avl = gpr_avl_add(avl, box(48), box(2248)); - avl = gpr_avl_add(avl, box(138), box(2249)); - avl = gpr_avl_add(avl, box(437), box(2250)); - avl = gpr_avl_add(avl, box(275), box(2251)); + avl = gpr_avl_add(avl, box(48), box(2248), NULL); + avl = gpr_avl_add(avl, box(138), box(2249), NULL); + avl = gpr_avl_add(avl, box(437), box(2250), NULL); + avl = gpr_avl_add(avl, box(275), box(2251), NULL); avl = remove_int(avl, 520); - avl = gpr_avl_add(avl, box(1019), box(2253)); + avl = gpr_avl_add(avl, box(1019), box(2253), NULL); avl = remove_int(avl, 955); - avl = gpr_avl_add(avl, box(270), box(2255)); + avl = gpr_avl_add(avl, box(270), box(2255), NULL); avl = remove_int(avl, 680); avl = remove_int(avl, 698); - avl = gpr_avl_add(avl, box(735), box(2258)); - avl = gpr_avl_add(avl, box(400), box(2259)); + avl = gpr_avl_add(avl, box(735), box(2258), NULL); + avl = gpr_avl_add(avl, box(400), box(2259), NULL); avl = remove_int(avl, 991); - avl = gpr_avl_add(avl, box(263), box(2261)); + avl = gpr_avl_add(avl, box(263), box(2261), NULL); avl = remove_int(avl, 704); - avl = gpr_avl_add(avl, box(757), box(2263)); + avl = gpr_avl_add(avl, box(757), box(2263), NULL); avl = remove_int(avl, 194); avl = remove_int(avl, 616); avl = remove_int(avl, 784); - avl = gpr_avl_add(avl, box(382), box(2267)); - avl = gpr_avl_add(avl, box(464), box(2268)); - avl = gpr_avl_add(avl, box(817), box(2269)); + avl = gpr_avl_add(avl, box(382), box(2267), NULL); + avl = gpr_avl_add(avl, box(464), box(2268), NULL); + avl = gpr_avl_add(avl, box(817), box(2269), NULL); avl = remove_int(avl, 445); - avl = gpr_avl_add(avl, box(412), box(2271)); + avl = gpr_avl_add(avl, box(412), box(2271), NULL); avl = remove_int(avl, 525); - avl = gpr_avl_add(avl, box(299), box(2273)); - avl = gpr_avl_add(avl, box(464), box(2274)); - avl = gpr_avl_add(avl, box(715), box(2275)); + avl = gpr_avl_add(avl, box(299), box(2273), NULL); + avl = gpr_avl_add(avl, box(464), box(2274), NULL); + avl = gpr_avl_add(avl, box(715), box(2275), NULL); avl = remove_int(avl, 58); avl = remove_int(avl, 218); - avl = gpr_avl_add(avl, box(961), box(2278)); - avl = gpr_avl_add(avl, box(491), box(2279)); + avl = gpr_avl_add(avl, box(961), box(2278), NULL); + avl = gpr_avl_add(avl, box(491), box(2279), NULL); avl = remove_int(avl, 846); - avl = gpr_avl_add(avl, box(762), box(2281)); + avl = gpr_avl_add(avl, box(762), box(2281), NULL); avl = remove_int(avl, 974); avl = remove_int(avl, 887); - avl = gpr_avl_add(avl, box(498), box(2284)); + avl = gpr_avl_add(avl, box(498), box(2284), NULL); avl = remove_int(avl, 810); avl = remove_int(avl, 743); avl = remove_int(avl, 22); avl = remove_int(avl, 284); - avl = gpr_avl_add(avl, box(482), box(2289)); - avl = gpr_avl_add(avl, box(1021), box(2290)); + avl = gpr_avl_add(avl, box(482), box(2289), NULL); + avl = gpr_avl_add(avl, box(1021), box(2290), NULL); avl = remove_int(avl, 155); avl = remove_int(avl, 128); - avl = gpr_avl_add(avl, box(819), box(2293)); - avl = gpr_avl_add(avl, box(324), box(2294)); + avl = gpr_avl_add(avl, box(819), box(2293), NULL); + avl = gpr_avl_add(avl, box(324), box(2294), NULL); avl = remove_int(avl, 196); avl = remove_int(avl, 370); avl = remove_int(avl, 753); avl = remove_int(avl, 56); avl = remove_int(avl, 735); - avl = gpr_avl_add(avl, box(272), box(2300)); - avl = gpr_avl_add(avl, box(474), box(2301)); - avl = gpr_avl_add(avl, box(719), box(2302)); - avl = gpr_avl_add(avl, box(236), box(2303)); + avl = gpr_avl_add(avl, box(272), box(2300), NULL); + avl = gpr_avl_add(avl, box(474), box(2301), NULL); + avl = gpr_avl_add(avl, box(719), box(2302), NULL); + avl = gpr_avl_add(avl, box(236), box(2303), NULL); avl = remove_int(avl, 818); - avl = gpr_avl_add(avl, box(727), box(2305)); + avl = gpr_avl_add(avl, box(727), box(2305), NULL); avl = remove_int(avl, 892); avl = remove_int(avl, 871); avl = remove_int(avl, 231); - avl = gpr_avl_add(avl, box(62), box(2309)); - avl = gpr_avl_add(avl, box(953), box(2310)); + avl = gpr_avl_add(avl, box(62), box(2309), NULL); + avl = gpr_avl_add(avl, box(953), box(2310), NULL); avl = remove_int(avl, 701); - avl = gpr_avl_add(avl, box(193), box(2312)); + avl = gpr_avl_add(avl, box(193), box(2312), NULL); avl = remove_int(avl, 619); avl = remove_int(avl, 22); avl = remove_int(avl, 804); avl = remove_int(avl, 851); - avl = gpr_avl_add(avl, box(286), box(2317)); - avl = gpr_avl_add(avl, box(751), box(2318)); + avl = gpr_avl_add(avl, box(286), box(2317), NULL); + avl = gpr_avl_add(avl, box(751), box(2318), NULL); avl = remove_int(avl, 525); - avl = gpr_avl_add(avl, box(217), box(2320)); + avl = gpr_avl_add(avl, box(217), box(2320), NULL); avl = remove_int(avl, 336); - avl = gpr_avl_add(avl, box(86), box(2322)); - avl = gpr_avl_add(avl, box(81), box(2323)); - avl = gpr_avl_add(avl, box(850), box(2324)); + avl = gpr_avl_add(avl, box(86), box(2322), NULL); + avl = gpr_avl_add(avl, box(81), box(2323), NULL); + avl = gpr_avl_add(avl, box(850), box(2324), NULL); avl = remove_int(avl, 872); - avl = gpr_avl_add(avl, box(402), box(2326)); - avl = gpr_avl_add(avl, box(54), box(2327)); - avl = gpr_avl_add(avl, box(980), box(2328)); - avl = gpr_avl_add(avl, box(845), box(2329)); + avl = gpr_avl_add(avl, box(402), box(2326), NULL); + avl = gpr_avl_add(avl, box(54), box(2327), NULL); + avl = gpr_avl_add(avl, box(980), box(2328), NULL); + avl = gpr_avl_add(avl, box(845), box(2329), NULL); avl = remove_int(avl, 1004); avl = remove_int(avl, 273); avl = remove_int(avl, 879); - avl = gpr_avl_add(avl, box(354), box(2333)); - avl = gpr_avl_add(avl, box(58), box(2334)); - avl = gpr_avl_add(avl, box(127), box(2335)); + avl = gpr_avl_add(avl, box(354), box(2333), NULL); + avl = gpr_avl_add(avl, box(58), box(2334), NULL); + avl = gpr_avl_add(avl, box(127), box(2335), NULL); avl = remove_int(avl, 84); - avl = gpr_avl_add(avl, box(360), box(2337)); + avl = gpr_avl_add(avl, box(360), box(2337), NULL); avl = remove_int(avl, 648); avl = remove_int(avl, 488); avl = remove_int(avl, 585); avl = remove_int(avl, 230); - avl = gpr_avl_add(avl, box(887), box(2342)); + avl = gpr_avl_add(avl, box(887), box(2342), NULL); avl = remove_int(avl, 558); avl = remove_int(avl, 958); - avl = gpr_avl_add(avl, box(822), box(2345)); + avl = gpr_avl_add(avl, box(822), box(2345), NULL); avl = remove_int(avl, 1004); avl = remove_int(avl, 747); - avl = gpr_avl_add(avl, box(631), box(2348)); - avl = gpr_avl_add(avl, box(442), box(2349)); + avl = gpr_avl_add(avl, box(631), box(2348), NULL); + avl = gpr_avl_add(avl, box(442), box(2349), NULL); avl = remove_int(avl, 957); avl = remove_int(avl, 964); - avl = gpr_avl_add(avl, box(10), box(2352)); + avl = gpr_avl_add(avl, box(10), box(2352), NULL); avl = remove_int(avl, 189); - avl = gpr_avl_add(avl, box(742), box(2354)); + avl = gpr_avl_add(avl, box(742), box(2354), NULL); avl = remove_int(avl, 108); - avl = gpr_avl_add(avl, box(1014), box(2356)); + avl = gpr_avl_add(avl, box(1014), box(2356), NULL); avl = remove_int(avl, 266); avl = remove_int(avl, 623); avl = remove_int(avl, 697); - avl = gpr_avl_add(avl, box(180), box(2360)); + avl = gpr_avl_add(avl, box(180), box(2360), NULL); avl = remove_int(avl, 472); - avl = gpr_avl_add(avl, box(567), box(2362)); + avl = gpr_avl_add(avl, box(567), box(2362), NULL); avl = remove_int(avl, 1020); avl = remove_int(avl, 273); - avl = gpr_avl_add(avl, box(864), box(2365)); - avl = gpr_avl_add(avl, box(1009), box(2366)); + avl = gpr_avl_add(avl, box(864), box(2365), NULL); + avl = gpr_avl_add(avl, box(1009), box(2366), NULL); avl = remove_int(avl, 224); avl = remove_int(avl, 81); - avl = gpr_avl_add(avl, box(653), box(2369)); + avl = gpr_avl_add(avl, box(653), box(2369), NULL); avl = remove_int(avl, 67); avl = remove_int(avl, 102); avl = remove_int(avl, 76); @@ -3513,51 +3515,51 @@ static void test_badcase3(void) { avl = remove_int(avl, 169); avl = remove_int(avl, 232); avl = remove_int(avl, 79); - avl = gpr_avl_add(avl, box(509), box(2377)); + avl = gpr_avl_add(avl, box(509), box(2377), NULL); avl = remove_int(avl, 900); avl = remove_int(avl, 822); avl = remove_int(avl, 945); avl = remove_int(avl, 356); - avl = gpr_avl_add(avl, box(443), box(2382)); - avl = gpr_avl_add(avl, box(925), box(2383)); + avl = gpr_avl_add(avl, box(443), box(2382), NULL); + avl = gpr_avl_add(avl, box(925), box(2383), NULL); avl = remove_int(avl, 994); avl = remove_int(avl, 324); - avl = gpr_avl_add(avl, box(291), box(2386)); + avl = gpr_avl_add(avl, box(291), box(2386), NULL); avl = remove_int(avl, 94); avl = remove_int(avl, 795); avl = remove_int(avl, 42); - avl = gpr_avl_add(avl, box(613), box(2390)); + avl = gpr_avl_add(avl, box(613), box(2390), NULL); avl = remove_int(avl, 289); - avl = gpr_avl_add(avl, box(980), box(2392)); + avl = gpr_avl_add(avl, box(980), box(2392), NULL); avl = remove_int(avl, 316); - avl = gpr_avl_add(avl, box(281), box(2394)); - avl = gpr_avl_add(avl, box(1006), box(2395)); + avl = gpr_avl_add(avl, box(281), box(2394), NULL); + avl = gpr_avl_add(avl, box(1006), box(2395), NULL); avl = remove_int(avl, 776); - avl = gpr_avl_add(avl, box(108), box(2397)); - avl = gpr_avl_add(avl, box(918), box(2398)); + avl = gpr_avl_add(avl, box(108), box(2397), NULL); + avl = gpr_avl_add(avl, box(918), box(2398), NULL); avl = remove_int(avl, 721); avl = remove_int(avl, 563); - avl = gpr_avl_add(avl, box(925), box(2401)); + avl = gpr_avl_add(avl, box(925), box(2401), NULL); avl = remove_int(avl, 448); avl = remove_int(avl, 198); avl = remove_int(avl, 1); - avl = gpr_avl_add(avl, box(160), box(2405)); + avl = gpr_avl_add(avl, box(160), box(2405), NULL); avl = remove_int(avl, 515); - avl = gpr_avl_add(avl, box(284), box(2407)); - avl = gpr_avl_add(avl, box(225), box(2408)); + avl = gpr_avl_add(avl, box(284), box(2407), NULL); + avl = gpr_avl_add(avl, box(225), box(2408), NULL); avl = remove_int(avl, 304); - avl = gpr_avl_add(avl, box(714), box(2410)); - avl = gpr_avl_add(avl, box(708), box(2411)); - avl = gpr_avl_add(avl, box(624), box(2412)); + avl = gpr_avl_add(avl, box(714), box(2410), NULL); + avl = gpr_avl_add(avl, box(708), box(2411), NULL); + avl = gpr_avl_add(avl, box(624), box(2412), NULL); avl = remove_int(avl, 662); avl = remove_int(avl, 825); avl = remove_int(avl, 383); avl = remove_int(avl, 381); - avl = gpr_avl_add(avl, box(194), box(2417)); + avl = gpr_avl_add(avl, box(194), box(2417), NULL); avl = remove_int(avl, 280); avl = remove_int(avl, 25); avl = remove_int(avl, 633); - avl = gpr_avl_add(avl, box(897), box(2421)); + avl = gpr_avl_add(avl, box(897), box(2421), NULL); avl = remove_int(avl, 636); avl = remove_int(avl, 596); avl = remove_int(avl, 757); @@ -3567,33 +3569,33 @@ static void test_badcase3(void) { avl = remove_int(avl, 843); avl = remove_int(avl, 280); avl = remove_int(avl, 911); - avl = gpr_avl_add(avl, box(1008), box(2431)); + avl = gpr_avl_add(avl, box(1008), box(2431), NULL); avl = remove_int(avl, 948); avl = remove_int(avl, 74); avl = remove_int(avl, 571); - avl = gpr_avl_add(avl, box(486), box(2435)); - avl = gpr_avl_add(avl, box(285), box(2436)); + avl = gpr_avl_add(avl, box(486), box(2435), NULL); + avl = gpr_avl_add(avl, box(285), box(2436), NULL); avl = remove_int(avl, 304); avl = remove_int(avl, 516); - avl = gpr_avl_add(avl, box(758), box(2439)); - avl = gpr_avl_add(avl, box(776), box(2440)); + avl = gpr_avl_add(avl, box(758), box(2439), NULL); + avl = gpr_avl_add(avl, box(776), box(2440), NULL); avl = remove_int(avl, 696); - avl = gpr_avl_add(avl, box(104), box(2442)); - avl = gpr_avl_add(avl, box(700), box(2443)); - avl = gpr_avl_add(avl, box(114), box(2444)); - avl = gpr_avl_add(avl, box(567), box(2445)); + avl = gpr_avl_add(avl, box(104), box(2442), NULL); + avl = gpr_avl_add(avl, box(700), box(2443), NULL); + avl = gpr_avl_add(avl, box(114), box(2444), NULL); + avl = gpr_avl_add(avl, box(567), box(2445), NULL); avl = remove_int(avl, 620); - avl = gpr_avl_add(avl, box(270), box(2447)); + avl = gpr_avl_add(avl, box(270), box(2447), NULL); avl = remove_int(avl, 730); - avl = gpr_avl_add(avl, box(749), box(2449)); - avl = gpr_avl_add(avl, box(443), box(2450)); + avl = gpr_avl_add(avl, box(749), box(2449), NULL); + avl = gpr_avl_add(avl, box(443), box(2450), NULL); avl = remove_int(avl, 457); - avl = gpr_avl_add(avl, box(571), box(2452)); - avl = gpr_avl_add(avl, box(626), box(2453)); + avl = gpr_avl_add(avl, box(571), box(2452), NULL); + avl = gpr_avl_add(avl, box(626), box(2453), NULL); avl = remove_int(avl, 638); avl = remove_int(avl, 313); - gpr_avl_unref(avl); + gpr_avl_unref(avl, NULL); } static void test_stress(int amount_of_stress) { @@ -3616,9 +3618,9 @@ static void test_stress(int amount_of_stress) { GPR_ASSERT(i); if (rand() < RAND_MAX / 2) { added[idx] = i; - printf("avl = gpr_avl_add(avl, box(%d), box(%d)); /* d=%d */\n", idx, i, - deletions); - avl = gpr_avl_add(avl, box(idx), box(i)); + printf("avl = gpr_avl_add(avl, box(%d), box(%d), NULL); /* d=%d */\n", + idx, i, deletions); + avl = gpr_avl_add(avl, box(idx), box(i), NULL); } else { deletions += (added[idx] != 0); added[idx] = 0; @@ -3634,7 +3636,7 @@ static void test_stress(int amount_of_stress) { } } - gpr_avl_unref(avl); + gpr_avl_unref(avl, NULL); } int main(int argc, char *argv[]) { From 16149ad456834eb18afe04d78bd0c2ea097a86a3 Mon Sep 17 00:00:00 2001 From: yang-g Date: Mon, 17 Jul 2017 15:13:24 -0700 Subject: [PATCH 094/127] regenerate projects --- src/ruby/ext/grpc/rb_grpc_imports.generated.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.h b/src/ruby/ext/grpc/rb_grpc_imports.generated.h index a477ab65073..52887043502 100644 --- a/src/ruby/ext/grpc/rb_grpc_imports.generated.h +++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.h @@ -644,22 +644,22 @@ extern gpr_get_allocation_functions_type gpr_get_allocation_functions_import; typedef gpr_avl(*gpr_avl_create_type)(const gpr_avl_vtable *vtable); extern gpr_avl_create_type gpr_avl_create_import; #define gpr_avl_create gpr_avl_create_import -typedef gpr_avl(*gpr_avl_ref_type)(gpr_avl avl); +typedef gpr_avl(*gpr_avl_ref_type)(gpr_avl avl, void *user_data); extern gpr_avl_ref_type gpr_avl_ref_import; #define gpr_avl_ref gpr_avl_ref_import -typedef void(*gpr_avl_unref_type)(gpr_avl avl); +typedef void(*gpr_avl_unref_type)(gpr_avl avl, void *user_data); extern gpr_avl_unref_type gpr_avl_unref_import; #define gpr_avl_unref gpr_avl_unref_import -typedef gpr_avl(*gpr_avl_add_type)(gpr_avl avl, void *key, void *value); +typedef gpr_avl(*gpr_avl_add_type)(gpr_avl avl, void *key, void *value, void *user_data); extern gpr_avl_add_type gpr_avl_add_import; #define gpr_avl_add gpr_avl_add_import -typedef gpr_avl(*gpr_avl_remove_type)(gpr_avl avl, void *key); +typedef gpr_avl(*gpr_avl_remove_type)(gpr_avl avl, void *key, void *user_data); extern gpr_avl_remove_type gpr_avl_remove_import; #define gpr_avl_remove gpr_avl_remove_import -typedef void *(*gpr_avl_get_type)(gpr_avl avl, void *key); +typedef void *(*gpr_avl_get_type)(gpr_avl avl, void *key, void *user_data); extern gpr_avl_get_type gpr_avl_get_import; #define gpr_avl_get gpr_avl_get_import -typedef int(*gpr_avl_maybe_get_type)(gpr_avl avl, void *key, void **value); +typedef int(*gpr_avl_maybe_get_type)(gpr_avl avl, void *key, void **value, void *user_data); extern gpr_avl_maybe_get_type gpr_avl_maybe_get_import; #define gpr_avl_maybe_get gpr_avl_maybe_get_import typedef int(*gpr_avl_is_empty_type)(gpr_avl avl); From d66ee1a0a8eac79e2cfbee7ea82a2de63492c5a1 Mon Sep 17 00:00:00 2001 From: yang-g Date: Tue, 18 Jul 2017 08:11:10 -0700 Subject: [PATCH 095/127] Remove unused user_data from ref_node. --- src/core/lib/support/avl.c | 88 +++++++++++++++++--------------------- 1 file changed, 40 insertions(+), 48 deletions(-) diff --git a/src/core/lib/support/avl.c b/src/core/lib/support/avl.c index a58551e259e..0e28b24c98e 100644 --- a/src/core/lib/support/avl.c +++ b/src/core/lib/support/avl.c @@ -32,7 +32,7 @@ gpr_avl gpr_avl_create(const gpr_avl_vtable *vtable) { return out; } -static gpr_avl_node *ref_node(gpr_avl_node *node, void *user_data) { +static gpr_avl_node *ref_node(gpr_avl_node *node) { if (node) { gpr_ref(&node->refs); } @@ -122,11 +122,10 @@ int gpr_avl_maybe_get(gpr_avl avl, void *key, void **value, void *user_data) { static gpr_avl_node *rotate_left(const gpr_avl_vtable *vtable, void *key, void *value, gpr_avl_node *left, gpr_avl_node *right, void *user_data) { - gpr_avl_node *n = - new_node(vtable->copy_key(right->key, user_data), - vtable->copy_value(right->value, user_data), - new_node(key, value, left, ref_node(right->left, user_data)), - ref_node(right->right, user_data)); + gpr_avl_node *n = new_node(vtable->copy_key(right->key, user_data), + vtable->copy_value(right->value, user_data), + new_node(key, value, left, ref_node(right->left)), + ref_node(right->right)); unref_node(vtable, right, user_data); return n; } @@ -136,9 +135,8 @@ static gpr_avl_node *rotate_right(const gpr_avl_vtable *vtable, void *key, gpr_avl_node *right, void *user_data) { gpr_avl_node *n = new_node(vtable->copy_key(left->key, user_data), - vtable->copy_value(left->value, user_data), - ref_node(left->left, user_data), - new_node(key, value, ref_node(left->right, user_data), right)); + vtable->copy_value(left->value, user_data), ref_node(left->left), + new_node(key, value, ref_node(left->right), right)); unref_node(vtable, left, user_data); return n; } @@ -147,14 +145,13 @@ static gpr_avl_node *rotate_left_right(const gpr_avl_vtable *vtable, void *key, void *value, gpr_avl_node *left, gpr_avl_node *right, void *user_data) { /* rotate_right(..., rotate_left(left), right) */ - gpr_avl_node *n = new_node( - vtable->copy_key(left->right->key, user_data), - vtable->copy_value(left->right->value, user_data), - new_node(vtable->copy_key(left->key, user_data), - vtable->copy_value(left->value, user_data), - ref_node(left->left, user_data), - ref_node(left->right->left, user_data)), - new_node(key, value, ref_node(left->right->right, user_data), right)); + gpr_avl_node *n = + new_node(vtable->copy_key(left->right->key, user_data), + vtable->copy_value(left->right->value, user_data), + new_node(vtable->copy_key(left->key, user_data), + vtable->copy_value(left->value, user_data), + ref_node(left->left), ref_node(left->right->left)), + new_node(key, value, ref_node(left->right->right), right)); unref_node(vtable, left, user_data); return n; } @@ -163,14 +160,13 @@ static gpr_avl_node *rotate_right_left(const gpr_avl_vtable *vtable, void *key, void *value, gpr_avl_node *left, gpr_avl_node *right, void *user_data) { /* rotate_left(..., left, rotate_right(right)) */ - gpr_avl_node *n = new_node( - vtable->copy_key(right->left->key, user_data), - vtable->copy_value(right->left->value, user_data), - new_node(key, value, left, ref_node(right->left->left, user_data)), - new_node(vtable->copy_key(right->key, user_data), - vtable->copy_value(right->value, user_data), - ref_node(right->left->right, user_data), - ref_node(right->right, user_data))); + gpr_avl_node *n = + new_node(vtable->copy_key(right->left->key, user_data), + vtable->copy_value(right->left->value, user_data), + new_node(key, value, left, ref_node(right->left->left)), + new_node(vtable->copy_key(right->key, user_data), + vtable->copy_value(right->value, user_data), + ref_node(right->left->right), ref_node(right->right))); unref_node(vtable, right, user_data); return n; } @@ -208,19 +204,17 @@ static gpr_avl_node *add_key(const gpr_avl_vtable *vtable, gpr_avl_node *node, } cmp = vtable->compare_keys(node->key, key, user_data); if (cmp == 0) { - return new_node(key, value, ref_node(node->left, user_data), - ref_node(node->right, user_data)); + return new_node(key, value, ref_node(node->left), ref_node(node->right)); } else if (cmp > 0) { return rebalance(vtable, vtable->copy_key(node->key, user_data), vtable->copy_value(node->value, user_data), add_key(vtable, node->left, key, value, user_data), - ref_node(node->right, user_data), user_data); + ref_node(node->right), user_data); } else { - return rebalance(vtable, vtable->copy_key(node->key, user_data), - vtable->copy_value(node->value, user_data), - ref_node(node->left, user_data), - add_key(vtable, node->right, key, value, user_data), - user_data); + return rebalance( + vtable, vtable->copy_key(node->key, user_data), + vtable->copy_value(node->value, user_data), ref_node(node->left), + add_key(vtable, node->right, key, value, user_data), user_data); } } @@ -256,34 +250,32 @@ static gpr_avl_node *remove_key(const gpr_avl_vtable *vtable, cmp = vtable->compare_keys(node->key, key, user_data); if (cmp == 0) { if (node->left == NULL) { - return ref_node(node->right, user_data); + return ref_node(node->right); } else if (node->right == NULL) { - return ref_node(node->left, user_data); + return ref_node(node->left); } else if (node->left->height < node->right->height) { gpr_avl_node *h = in_order_head(node->right); - return rebalance(vtable, vtable->copy_key(h->key, user_data), - vtable->copy_value(h->value, user_data), - ref_node(node->left, user_data), - remove_key(vtable, node->right, h->key, user_data), - user_data); + return rebalance( + vtable, vtable->copy_key(h->key, user_data), + vtable->copy_value(h->value, user_data), ref_node(node->left), + remove_key(vtable, node->right, h->key, user_data), user_data); } else { gpr_avl_node *h = in_order_tail(node->left); return rebalance(vtable, vtable->copy_key(h->key, user_data), vtable->copy_value(h->value, user_data), remove_key(vtable, node->left, h->key, user_data), - ref_node(node->right, user_data), user_data); + ref_node(node->right), user_data); } } else if (cmp > 0) { return rebalance(vtable, vtable->copy_key(node->key, user_data), vtable->copy_value(node->value, user_data), remove_key(vtable, node->left, key, user_data), - ref_node(node->right, user_data), user_data); + ref_node(node->right), user_data); } else { - return rebalance(vtable, vtable->copy_key(node->key, user_data), - vtable->copy_value(node->value, user_data), - ref_node(node->left, user_data), - remove_key(vtable, node->right, key, user_data), - user_data); + return rebalance( + vtable, vtable->copy_key(node->key, user_data), + vtable->copy_value(node->value, user_data), ref_node(node->left), + remove_key(vtable, node->right, key, user_data), user_data); } } @@ -296,7 +288,7 @@ gpr_avl gpr_avl_remove(gpr_avl avl, void *key, void *user_data) { } gpr_avl gpr_avl_ref(gpr_avl avl, void *user_data) { - ref_node(avl.root, user_data); + ref_node(avl.root); return avl; } From 1a4890705d3efbd5496bc5a0967ada72c1b7af25 Mon Sep 17 00:00:00 2001 From: yang-g Date: Wed, 19 Jul 2017 10:52:29 -0700 Subject: [PATCH 096/127] format code --- src/core/ext/filters/client_channel/subchannel_index.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core/ext/filters/client_channel/subchannel_index.c b/src/core/ext/filters/client_channel/subchannel_index.c index 15e42980af0..ababd05d842 100644 --- a/src/core/ext/filters/client_channel/subchannel_index.c +++ b/src/core/ext/filters/client_channel/subchannel_index.c @@ -187,7 +187,6 @@ grpc_subchannel *grpc_subchannel_index_register(grpc_exec_ctx *exec_ctx, gpr_avl_unref(index, exec_ctx); } - if (need_to_unref_constructed) { GRPC_SUBCHANNEL_UNREF(exec_ctx, constructed, "index_register"); } From 303de0ae714d6a1d60b4ce7b8c582f27a4e9892b Mon Sep 17 00:00:00 2001 From: yang-g Date: Tue, 25 Jul 2017 07:50:45 -0700 Subject: [PATCH 097/127] update comments --- include/grpc/support/avl.h | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/include/grpc/support/avl.h b/include/grpc/support/avl.h index cd029ef2a6c..d53ff5d9040 100644 --- a/include/grpc/support/avl.h +++ b/include/grpc/support/avl.h @@ -58,29 +58,34 @@ typedef struct gpr_avl { gpr_avl_node *root; } gpr_avl; -/** create an immutable AVL tree */ +/** Create an immutable AVL tree. */ GPRAPI gpr_avl gpr_avl_create(const gpr_avl_vtable *vtable); -/** add a reference to an existing tree - returns - the tree as a convenience */ +/** Add a reference to an existing tree - returns + the tree as a convenience. The optional user_data will be passed to vtable + functions. */ GPRAPI gpr_avl gpr_avl_ref(gpr_avl avl, void *user_data); -/** remove a reference to a tree - destroying it if there - are no references left */ +/** Remove a reference to a tree - destroying it if there + are no references left. The optional user_data will be passed to vtable + functions. */ GPRAPI void gpr_avl_unref(gpr_avl avl, void *user_data); -/** return a new tree with (key, value) added to avl. +/** Return a new tree with (key, value) added to avl. implicitly unrefs avl to allow easy chaining. if key exists in avl, the new tree's key entry updated - (i.e. a duplicate is not created) */ + (i.e. a duplicate is not created). The optional user_data will be passed to + vtable functions. */ GPRAPI gpr_avl gpr_avl_add(gpr_avl avl, void *key, void *value, void *user_data); -/** return a new tree with key deleted - implicitly unrefs avl to allow easy chaining. */ +/** Return a new tree with key deleted + implicitly unrefs avl to allow easy chaining. The optional user_data will be + passed to vtable functions. */ GPRAPI gpr_avl gpr_avl_remove(gpr_avl avl, void *key, void *user_data); -/** lookup key, and return the associated value. - does not mutate avl. - returns NULL if key is not found. */ +/** Lookup key, and return the associated value. + Does not mutate avl. + Returns NULL if key is not found. The optional user_data will be passed to + vtable functions.*/ GPRAPI void *gpr_avl_get(gpr_avl avl, void *key, void *user_data); /** Return 1 if avl contains key, 0 otherwise; if it has the key, sets *value to - its value*/ + its value. THe optional user_data will be passed to vtable functions. */ GPRAPI int gpr_avl_maybe_get(gpr_avl avl, void *key, void **value, void *user_data); /** Return 1 if avl is empty, 0 otherwise */ From 69b7231776dc42c87abad33430c66e7b302bf00c Mon Sep 17 00:00:00 2001 From: Nathaniel Manista Date: Fri, 21 Jul 2017 03:18:11 +0000 Subject: [PATCH 098/127] gRPC Python test infrastructure (The time-related first part of it, anyway.) --- .pylintrc | 5 + .../grpcio_testing/grpc_testing/__init__.py | 119 ++++++++++ .../grpcio_testing/grpc_testing/_time.py | 224 ++++++++++++++++++ src/python/grpcio_testing/grpc_version.py | 17 ++ src/python/grpcio_testing/setup.py | 44 ++++ .../grpcio_tests/tests/testing/__init__.py | 13 + .../grpcio_tests/tests/testing/_time_test.py | 165 +++++++++++++ src/python/grpcio_tests/tests/tests.json | 2 + tools/distrib/pylint_code.sh | 1 + tools/distrib/yapf_code.sh | 1 + .../run_tests/helper_scripts/build_python.sh | 3 + 11 files changed, 594 insertions(+) create mode 100644 src/python/grpcio_testing/grpc_testing/__init__.py create mode 100644 src/python/grpcio_testing/grpc_testing/_time.py create mode 100644 src/python/grpcio_testing/grpc_version.py create mode 100644 src/python/grpcio_testing/setup.py create mode 100644 src/python/grpcio_tests/tests/testing/__init__.py create mode 100644 src/python/grpcio_tests/tests/testing/_time_test.py diff --git a/.pylintrc b/.pylintrc index 8447821b4e5..05b4e685fb0 100644 --- a/.pylintrc +++ b/.pylintrc @@ -41,6 +41,11 @@ disable= # NOTE(nathaniel): We don't write doc strings for most private code # elements. missing-docstring, + # NOTE(nathaniel): In numeric comparisons it is better to have the + # lesser (or lesser-or-equal-to) quantity on the left when the + # expression is true than it is to worry about which is an identifier + # and which a literal value. + misplaced-comparison-constant, # NOTE(nathaniel): Our completely abstract interface classes don't have # constructors. no-init, diff --git a/src/python/grpcio_testing/grpc_testing/__init__.py b/src/python/grpcio_testing/grpc_testing/__init__.py new file mode 100644 index 00000000000..c5a17f457a4 --- /dev/null +++ b/src/python/grpcio_testing/grpc_testing/__init__.py @@ -0,0 +1,119 @@ +# Copyright 2017 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Objects for use in testing gRPC Python-using application code.""" + +import abc + +import six + +import grpc + + +class Time(six.with_metaclass(abc.ABCMeta)): + """A simulation of time. + + Implementations needn't be connected with real time as provided by the + Python interpreter, but as long as systems under test use + RpcContext.is_active and RpcContext.time_remaining for querying RPC liveness + implementations may be used to change passage of time in tests. + """ + + @abc.abstractmethod + def time(self): + """Accesses the current test time. + + Returns: + The current test time (over which this object has authority). + """ + raise NotImplementedError() + + @abc.abstractmethod + def call_in(self, behavior, delay): + """Adds a behavior to be called after some time. + + Args: + behavior: A behavior to be called with no arguments. + delay: A duration of time in seconds after which to call the behavior. + + Returns: + A grpc.Future with which the call of the behavior may be cancelled + before it is executed. + """ + raise NotImplementedError() + + @abc.abstractmethod + def call_at(self, behavior, time): + """Adds a behavior to be called at a specific time. + + Args: + behavior: A behavior to be called with no arguments. + time: The test time at which to call the behavior. + + Returns: + A grpc.Future with which the call of the behavior may be cancelled + before it is executed. + """ + raise NotImplementedError() + + @abc.abstractmethod + def sleep_for(self, duration): + """Blocks for some length of test time. + + Args: + duration: A duration of test time in seconds for which to block. + """ + raise NotImplementedError() + + @abc.abstractmethod + def sleep_until(self, time): + """Blocks until some test time. + + Args: + time: The test time until which to block. + """ + raise NotImplementedError() + + +def strict_real_time(): + """Creates a Time backed by the Python interpreter's time. + + The returned instance will be "strict" with respect to callbacks + submitted to it: it will ensure that all callbacks registered to + be called at time t have been called before it describes the time + as having advanced beyond t. + + Returns: + A Time backed by the "system" (Python interpreter's) time. + """ + from grpc_testing import _time + return _time.StrictRealTime() + + +def strict_fake_time(now): + """Creates a Time that can be manipulated by test code. + + The returned instance maintains an internal representation of time + independent of real time. This internal representation only advances + when user code calls the instance's sleep_for and sleep_until methods. + + The returned instance will be "strict" with respect to callbacks + submitted to it: it will ensure that all callbacks registered to + be called at time t have been called before it describes the time + as having advanced beyond t. + + Returns: + A Time that simulates the passage of time. + """ + from grpc_testing import _time + return _time.StrictFakeTime(now) diff --git a/src/python/grpcio_testing/grpc_testing/_time.py b/src/python/grpcio_testing/grpc_testing/_time.py new file mode 100644 index 00000000000..3b1ab4bcd86 --- /dev/null +++ b/src/python/grpcio_testing/grpc_testing/_time.py @@ -0,0 +1,224 @@ +# Copyright 2017 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Test times.""" + +import collections +import logging +import threading +import time as _time + +import grpc +import grpc_testing + + +def _call(behaviors): + for behavior in behaviors: + try: + behavior() + except Exception: # pylint: disable=broad-except + logging.exception('Exception calling behavior "%r"!', behavior) + + +def _call_in_thread(behaviors): + calling = threading.Thread(target=_call, args=(behaviors,)) + calling.start() + # NOTE(nathaniel): Because this function is called from "strict" Time + # implementations, it blocks until after all behaviors have terminated. + calling.join() + + +class _State(object): + + def __init__(self): + self.condition = threading.Condition() + self.times_to_behaviors = collections.defaultdict(list) + + +class _Delta( + collections.namedtuple('_Delta', + ('mature_behaviors', 'earliest_mature_time', + 'earliest_immature_time',))): + pass + + +def _process(state, now): + mature_behaviors = [] + earliest_mature_time = None + while state.times_to_behaviors: + earliest_time = min(state.times_to_behaviors) + if earliest_time <= now: + if earliest_mature_time is None: + earliest_mature_time = earliest_time + earliest_mature_behaviors = state.times_to_behaviors.pop( + earliest_time) + mature_behaviors.extend(earliest_mature_behaviors) + else: + earliest_immature_time = earliest_time + break + else: + earliest_immature_time = None + return _Delta(mature_behaviors, earliest_mature_time, + earliest_immature_time) + + +class _Future(grpc.Future): + + def __init__(self, state, behavior, time): + self._state = state + self._behavior = behavior + self._time = time + self._cancelled = False + + def cancel(self): + with self._state.condition: + if self._cancelled: + return True + else: + behaviors_at_time = self._state.times_to_behaviors.get( + self._time) + if behaviors_at_time is None: + return False + else: + behaviors_at_time.remove(self._behavior) + if not behaviors_at_time: + self._state.times_to_behaviors.pop(self._time) + self._state.condition.notify_all() + self._cancelled = True + return True + + def cancelled(self): + with self._state.condition: + return self._cancelled + + def running(self): + raise NotImplementedError() + + def done(self): + raise NotImplementedError() + + def result(self, timeout=None): + raise NotImplementedError() + + def exception(self, timeout=None): + raise NotImplementedError() + + def traceback(self, timeout=None): + raise NotImplementedError() + + def add_done_callback(self, fn): + raise NotImplementedError() + + +class StrictRealTime(grpc_testing.Time): + + def __init__(self): + self._state = _State() + self._active = False + self._calling = None + + def _activity(self): + while True: + with self._state.condition: + while True: + now = _time.time() + delta = _process(self._state, now) + self._state.condition.notify_all() + if delta.mature_behaviors: + self._calling = delta.earliest_mature_time + break + self._calling = None + if delta.earliest_immature_time is None: + self._active = False + return + else: + timeout = max(0, delta.earliest_immature_time - now) + self._state.condition.wait(timeout=timeout) + _call(delta.mature_behaviors) + + def _ensure_called_through(self, time): + with self._state.condition: + while ((self._state.times_to_behaviors and + min(self._state.times_to_behaviors) < time) or + (self._calling is not None and self._calling < time)): + self._state.condition.wait() + + def _call_at(self, behavior, time): + with self._state.condition: + self._state.times_to_behaviors[time].append(behavior) + if self._active: + self._state.condition.notify_all() + else: + activity = threading.Thread(target=self._activity) + activity.start() + self._active = True + return _Future(self._state, behavior, time) + + def time(self): + return _time.time() + + def call_in(self, behavior, delay): + return self._call_at(behavior, _time.time() + delay) + + def call_at(self, behavior, time): + return self._call_at(behavior, time) + + def sleep_for(self, duration): + time = _time.time() + duration + _time.sleep(duration) + self._ensure_called_through(time) + + def sleep_until(self, time): + _time.sleep(max(0, time - _time.time())) + self._ensure_called_through(time) + + +class StrictFakeTime(grpc_testing.Time): + + def __init__(self, time): + self._state = _State() + self._time = time + + def time(self): + return self._time + + def call_in(self, behavior, delay): + if delay <= 0: + _call_in_thread((behavior,)) + else: + with self._state.condition: + time = self._time + delay + self._state.times_to_behaviors[time].append(behavior) + return _Future(self._state, behavior, time) + + def call_at(self, behavior, time): + with self._state.condition: + if time <= self._time: + _call_in_thread((behavior,)) + else: + self._state.times_to_behaviors[time].append(behavior) + return _Future(self._state, behavior, time) + + def sleep_for(self, duration): + if 0 < duration: + with self._state.condition: + self._time += duration + delta = _process(self._state, self._time) + _call_in_thread(delta.mature_behaviors) + + def sleep_until(self, time): + with self._state.condition: + if self._time < time: + self._time = time + delta = _process(self._state, self._time) + _call_in_thread(delta.mature_behaviors) diff --git a/src/python/grpcio_testing/grpc_version.py b/src/python/grpcio_testing/grpc_version.py new file mode 100644 index 00000000000..41a75d46f68 --- /dev/null +++ b/src/python/grpcio_testing/grpc_version.py @@ -0,0 +1,17 @@ +# Copyright 2017 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_reflection/grpc_version.py.template`!!! + +VERSION = '1.5.0.dev0' diff --git a/src/python/grpcio_testing/setup.py b/src/python/grpcio_testing/setup.py new file mode 100644 index 00000000000..0cc336abd1f --- /dev/null +++ b/src/python/grpcio_testing/setup.py @@ -0,0 +1,44 @@ +# Copyright 2017 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Setup module for gRPC Python's testing package.""" + +import os +import sys + +import setuptools + +# Ensure we're in the proper directory whether or not we're being used by pip. +os.chdir(os.path.dirname(os.path.abspath(__file__))) + +# Break import style to ensure that we can find same-directory modules. +import grpc_version + +PACKAGE_DIRECTORIES = { + '': '.', +} + +INSTALL_REQUIRES = ('protobuf>=3.3.0', + 'grpcio>={version}'.format(version=grpc_version.VERSION),) + +setuptools.setup( + name='grpcio-testing', + version=grpc_version.VERSION, + license='Apache License 2.0', + description='Testing utilities for gRPC Python', + author='The gRPC Authors', + author_email='grpc-io@googlegroups.com', + url='https://grpc.io', + package_dir=PACKAGE_DIRECTORIES, + packages=setuptools.find_packages('.'), + install_requires=INSTALL_REQUIRES) diff --git a/src/python/grpcio_tests/tests/testing/__init__.py b/src/python/grpcio_tests/tests/testing/__init__.py new file mode 100644 index 00000000000..1e120359cf9 --- /dev/null +++ b/src/python/grpcio_tests/tests/testing/__init__.py @@ -0,0 +1,13 @@ +# Copyright 2017 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/src/python/grpcio_tests/tests/testing/_time_test.py b/src/python/grpcio_tests/tests/testing/_time_test.py new file mode 100644 index 00000000000..797394ae20f --- /dev/null +++ b/src/python/grpcio_tests/tests/testing/_time_test.py @@ -0,0 +1,165 @@ +# Copyright 2017 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import random +import threading +import time +import unittest + +import grpc_testing + +_QUANTUM = 0.3 +_MANY = 10000 +# Tests that run in real time can either wait for the scheduler to +# eventually run what needs to be run (and risk timing out) or declare +# that the scheduler didn't schedule work reasonably fast enough. We +# choose the latter for this test. +_PATHOLOGICAL_SCHEDULING = 'pathological thread scheduling!' + + +class _TimeNoter(object): + + def __init__(self, time): + self._condition = threading.Condition() + self._time = time + self._call_times = [] + + def __call__(self): + with self._condition: + self._call_times.append(self._time.time()) + + def call_times(self): + with self._condition: + return tuple(self._call_times) + + +class TimeTest(object): + + def test_sleep_for(self): + start_time = self._time.time() + self._time.sleep_for(_QUANTUM) + end_time = self._time.time() + + self.assertLessEqual(start_time + _QUANTUM, end_time) + + def test_sleep_until(self): + start_time = self._time.time() + self._time.sleep_until(start_time + _QUANTUM) + end_time = self._time.time() + + self.assertLessEqual(start_time + _QUANTUM, end_time) + + def test_call_in(self): + time_noter = _TimeNoter(self._time) + + start_time = self._time.time() + self._time.call_in(time_noter, _QUANTUM) + self._time.sleep_for(_QUANTUM * 2) + call_times = time_noter.call_times() + + self.assertTrue(call_times, msg=_PATHOLOGICAL_SCHEDULING) + self.assertLessEqual(start_time + _QUANTUM, call_times[0]) + + def test_call_at(self): + time_noter = _TimeNoter(self._time) + + start_time = self._time.time() + self._time.call_at(time_noter, self._time.time() + _QUANTUM) + self._time.sleep_for(_QUANTUM * 2) + call_times = time_noter.call_times() + + self.assertTrue(call_times, msg=_PATHOLOGICAL_SCHEDULING) + self.assertLessEqual(start_time + _QUANTUM, call_times[0]) + + def test_cancel(self): + time_noter = _TimeNoter(self._time) + + future = self._time.call_in(time_noter, _QUANTUM * 2) + self._time.sleep_for(_QUANTUM) + cancelled = future.cancel() + self._time.sleep_for(_QUANTUM * 2) + call_times = time_noter.call_times() + + self.assertFalse(call_times, msg=_PATHOLOGICAL_SCHEDULING) + self.assertTrue(cancelled) + self.assertTrue(future.cancelled()) + + def test_many(self): + test_events = tuple(threading.Event() for _ in range(_MANY)) + possibly_cancelled_futures = {} + background_noise_futures = [] + + for test_event in test_events: + possibly_cancelled_futures[test_event] = self._time.call_in( + test_event.set, _QUANTUM * (2 + random.random())) + for _ in range(_MANY): + background_noise_futures.append( + self._time.call_in(threading.Event().set, _QUANTUM * 1000 * + random.random())) + self._time.sleep_for(_QUANTUM) + cancelled = set() + for test_event, test_future in possibly_cancelled_futures.items(): + if bool(random.randint(0, 1)) and test_future.cancel(): + cancelled.add(test_event) + self._time.sleep_for(_QUANTUM * 3) + + for test_event in test_events: + (self.assertFalse if test_event in cancelled else + self.assertTrue)(test_event.is_set()) + for background_noise_future in background_noise_futures: + background_noise_future.cancel() + + def test_same_behavior_used_several_times(self): + time_noter = _TimeNoter(self._time) + + start_time = self._time.time() + first_future_at_one = self._time.call_in(time_noter, _QUANTUM) + second_future_at_one = self._time.call_in(time_noter, _QUANTUM) + first_future_at_three = self._time.call_in(time_noter, _QUANTUM * 3) + second_future_at_three = self._time.call_in(time_noter, _QUANTUM * 3) + self._time.sleep_for(_QUANTUM * 2) + first_future_at_one_cancelled = first_future_at_one.cancel() + second_future_at_one_cancelled = second_future_at_one.cancel() + first_future_at_three_cancelled = first_future_at_three.cancel() + self._time.sleep_for(_QUANTUM * 2) + second_future_at_three_cancelled = second_future_at_three.cancel() + first_future_at_three_cancelled_again = first_future_at_three.cancel() + call_times = time_noter.call_times() + + self.assertEqual(3, len(call_times), msg=_PATHOLOGICAL_SCHEDULING) + self.assertFalse(first_future_at_one_cancelled) + self.assertFalse(second_future_at_one_cancelled) + self.assertTrue(first_future_at_three_cancelled) + self.assertFalse(second_future_at_three_cancelled) + self.assertTrue(first_future_at_three_cancelled_again) + self.assertLessEqual(start_time + _QUANTUM, call_times[0]) + self.assertLessEqual(start_time + _QUANTUM, call_times[1]) + self.assertLessEqual(start_time + _QUANTUM * 3, call_times[2]) + + +class StrictRealTimeTest(TimeTest, unittest.TestCase): + + def setUp(self): + self._time = grpc_testing.strict_real_time() + + +class StrictFakeTimeTest(TimeTest, unittest.TestCase): + + def setUp(self): + self._time = grpc_testing.strict_fake_time( + random.randint(0, int(time.time()))) + + +if __name__ == '__main__': + unittest.main(verbosity=2) diff --git a/src/python/grpcio_tests/tests/tests.json b/src/python/grpcio_tests/tests/tests.json index 126e8ac60dd..f86eeb76c70 100644 --- a/src/python/grpcio_tests/tests/tests.json +++ b/src/python/grpcio_tests/tests/tests.json @@ -9,6 +9,8 @@ "protoc_plugin._split_definitions_test.SplitSeparateTest", "protoc_plugin.beta_python_plugin_test.PythonPluginTest", "reflection._reflection_servicer_test.ReflectionServicerTest", + "testing._time_test.StrictFakeTimeTest", + "testing._time_test.StrictRealTimeTest", "unit._api_test.AllTest", "unit._api_test.ChannelConnectivityTest", "unit._api_test.ChannelTest", diff --git a/tools/distrib/pylint_code.sh b/tools/distrib/pylint_code.sh index 3a1825535d5..3c9235b5480 100755 --- a/tools/distrib/pylint_code.sh +++ b/tools/distrib/pylint_code.sh @@ -22,6 +22,7 @@ DIRS=( 'src/python/grpcio/grpc' 'src/python/grpcio_health_checking/grpc_health' 'src/python/grpcio_reflection/grpc_reflection' + 'src/python/grpcio_testing/grpc_testing' ) VIRTUALENV=python_pylint_venv diff --git a/tools/distrib/yapf_code.sh b/tools/distrib/yapf_code.sh index 4f75163748c..dbb6b5c41f2 100755 --- a/tools/distrib/yapf_code.sh +++ b/tools/distrib/yapf_code.sh @@ -25,6 +25,7 @@ EXCLUSIONS=( 'grpcio/grpc_*.py' 'grpcio_health_checking/grpc_*.py' 'grpcio_reflection/grpc_*.py' + 'grpcio_testing/grpc_*.py' 'grpcio_tests/grpc_*.py' ) diff --git a/tools/run_tests/helper_scripts/build_python.sh b/tools/run_tests/helper_scripts/build_python.sh index 1c1034e475d..be650553dc8 100755 --- a/tools/run_tests/helper_scripts/build_python.sh +++ b/tools/run_tests/helper_scripts/build_python.sh @@ -171,6 +171,9 @@ $VENV_PYTHON $ROOT/src/python/grpcio_reflection/setup.py preprocess $VENV_PYTHON $ROOT/src/python/grpcio_reflection/setup.py build_package_protos pip_install_dir $ROOT/src/python/grpcio_reflection +# Install testing +pip_install_dir $ROOT/src/python/grpcio_testing + # Build/install tests $VENV_PYTHON -m pip install coverage==4.4 oauth2client==4.1.0 \ google-auth==1.0.0 requests==2.14.2 From 9bf8342a93a158f0c5c78eb2b3f347d518025b11 Mon Sep 17 00:00:00 2001 From: Sree Kuchibhotla Date: Tue, 25 Jul 2017 11:34:46 -0700 Subject: [PATCH 099/127] enable epollsig --- src/core/lib/iomgr/ev_epollsig_linux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/lib/iomgr/ev_epollsig_linux.c b/src/core/lib/iomgr/ev_epollsig_linux.c index 11067e39590..070d75e42a0 100644 --- a/src/core/lib/iomgr/ev_epollsig_linux.c +++ b/src/core/lib/iomgr/ev_epollsig_linux.c @@ -1730,7 +1730,7 @@ const grpc_event_engine_vtable *grpc_init_epollsig_linux( if (!is_grpc_wakeup_signal_initialized) { /* TODO(ctiller): when other epoll engines are ready, remove the true || to * force this to be explitly chosen if needed */ - if (explicit_request) { + if (true || explicit_request) { grpc_use_signal(SIGRTMIN + 6); } else { return NULL; From 9c420447fa73d139748a483336a923fba1419e0a Mon Sep 17 00:00:00 2001 From: Ken Payson Date: Tue, 25 Jul 2017 12:06:46 -0700 Subject: [PATCH 100/127] Add classifiers to package details --- setup.py | 13 +++++++++++++ src/python/grpcio_health_checking/setup.py | 13 +++++++++++++ src/python/grpcio_reflection/setup.py | 13 +++++++++++++ tools/distrib/python/grpcio_tools/setup.py | 13 +++++++++++++ 4 files changed, 52 insertions(+) diff --git a/setup.py b/setup.py index e42c8342ea6..403c13562cc 100644 --- a/setup.py +++ b/setup.py @@ -60,6 +60,18 @@ _spawn_patch.monkeypatch_spawn() LICENSE = 'Apache License 2.0' +CLASSIFIERS = [ + 'Development Status :: 5 - Production/Stable', + 'Programming Language :: Python', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'License :: OSI Approved :: Apache Software License', +], + # Environment variable to determine whether or not the Cython extension should # *use* Cython or use the generated C files. Note that this requires the C files # to have been generated by building first *with* Cython support. Even if this @@ -283,6 +295,7 @@ setuptools.setup( author_email='grpc-io@googlegroups.com', url='https://grpc.io', license=LICENSE, + classifiers=CLASSIFIERS, long_description=open(README).read(), ext_modules=CYTHON_EXTENSION_MODULES, packages=list(PACKAGES), diff --git a/src/python/grpcio_health_checking/setup.py b/src/python/grpcio_health_checking/setup.py index 83e0ead3910..0299b4cca95 100644 --- a/src/python/grpcio_health_checking/setup.py +++ b/src/python/grpcio_health_checking/setup.py @@ -24,6 +24,18 @@ os.chdir(os.path.dirname(os.path.abspath(__file__))) import health_commands import grpc_version +CLASSIFIERS = [ + 'Development Status :: 5 - Production/Stable', + 'Programming Language :: Python', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'License :: OSI Approved :: Apache Software License', +], + PACKAGE_DIRECTORIES = { '': '.', } @@ -48,6 +60,7 @@ setuptools.setup( author_email='grpc-io@googlegroups.com', url='https://grpc.io', license='Apache License 2.0', + classifiers=CLASSIFIERS, package_dir=PACKAGE_DIRECTORIES, packages=setuptools.find_packages('.'), install_requires=INSTALL_REQUIRES, diff --git a/src/python/grpcio_reflection/setup.py b/src/python/grpcio_reflection/setup.py index 20edbc4ec07..bed2311b598 100644 --- a/src/python/grpcio_reflection/setup.py +++ b/src/python/grpcio_reflection/setup.py @@ -25,6 +25,18 @@ os.chdir(os.path.dirname(os.path.abspath(__file__))) import reflection_commands import grpc_version +CLASSIFIERS = [ + 'Development Status :: 5 - Production/Stable', + 'Programming Language :: Python', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'License :: OSI Approved :: Apache Software License', +], + PACKAGE_DIRECTORIES = { '': '.', } @@ -48,6 +60,7 @@ setuptools.setup( description='Standard Protobuf Reflection Service for gRPC', author='The gRPC Authors', author_email='grpc-io@googlegroups.com', + classifiers=CLASSIFIERS, url='https://grpc.io', package_dir=PACKAGE_DIRECTORIES, packages=setuptools.find_packages('.'), diff --git a/tools/distrib/python/grpcio_tools/setup.py b/tools/distrib/python/grpcio_tools/setup.py index ddbb348e0cd..5c0329bff0c 100644 --- a/tools/distrib/python/grpcio_tools/setup.py +++ b/tools/distrib/python/grpcio_tools/setup.py @@ -37,6 +37,18 @@ sys.path.insert(0, os.path.abspath('.')) import protoc_lib_deps import grpc_version +CLASSIFIERS = [ + 'Development Status :: 5 - Production/Stable', + 'Programming Language :: Python', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'License :: OSI Approved :: Apache Software License', +], + PY3 = sys.version_info.major == 3 # Environment variable to determine whether or not the Cython extension should @@ -193,6 +205,7 @@ setuptools.setup( author_email='grpc-io@googlegroups.com', url='https://grpc.io', license='Apache License 2.0', + classifiers=CLASSIFIERS, ext_modules=extension_modules(), packages=setuptools.find_packages('.'), install_requires=[ From c22c65b58dd156620596d24524d77a504014d591 Mon Sep 17 00:00:00 2001 From: David Garcia Quintas Date: Tue, 25 Jul 2017 14:22:20 -0700 Subject: [PATCH 101/127] grpclb: deal with all-drops serverlists --- .../client_channel/lb_policy/grpclb/grpclb.c | 84 ++++++++++++------- .../lb_policy/round_robin/round_robin.c | 23 +++-- test/cpp/end2end/grpclb_end2end_test.cc | 42 +++++++++- 3 files changed, 107 insertions(+), 42 deletions(-) diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c index fdb18f687f3..ebce801b37c 100644 --- a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c +++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c @@ -491,11 +491,8 @@ static grpc_lb_addresses *process_serverlist_locked( for (size_t i = 0; i < serverlist->num_servers; ++i) { if (is_server_valid(serverlist->servers[i], i, true)) ++num_valid; } - if (num_valid == 0) return NULL; - grpc_lb_addresses *lb_addresses = grpc_lb_addresses_create(num_valid, &lb_token_vtable); - /* second pass: actually populate the addresses and LB tokens (aka user data * to the outside world) to be read by the RR policy during its creation. * Given that the validity tests are very cheap, they are performed again @@ -503,14 +500,12 @@ static grpc_lb_addresses *process_serverlist_locked( * incurr in an allocation due to the arbitrary number of server */ size_t addr_idx = 0; for (size_t sl_idx = 0; sl_idx < serverlist->num_servers; ++sl_idx) { - GPR_ASSERT(addr_idx < num_valid); const grpc_grpclb_server *server = serverlist->servers[sl_idx]; if (!is_server_valid(serverlist->servers[sl_idx], sl_idx, false)) continue; - + GPR_ASSERT(addr_idx < num_valid); /* address processing */ grpc_resolved_address addr; parse_server(server, &addr); - /* lb token processing */ void *user_data; if (server->has_load_balance_token) { @@ -596,7 +591,7 @@ static void update_lb_connectivity_status_locked( grpc_connectivity_state_name(rr_state), (void *)glb_policy->rr_policy); } grpc_connectivity_state_set(exec_ctx, &glb_policy->state_tracker, rr_state, - GRPC_ERROR_REF(rr_state_error), + rr_state_error, "update_lb_connectivity_status_locked"); } @@ -678,11 +673,12 @@ static bool pick_from_internal_rr_locked( static grpc_lb_policy_args *lb_policy_args_create(grpc_exec_ctx *exec_ctx, glb_lb_policy *glb_policy) { + grpc_lb_addresses *addresses = + process_serverlist_locked(exec_ctx, glb_policy->serverlist); + GPR_ASSERT(addresses != NULL); grpc_lb_policy_args *args = gpr_zalloc(sizeof(*args)); args->client_channel_factory = glb_policy->cc_factory; args->combiner = glb_policy->base.combiner; - grpc_lb_addresses *addresses = - process_serverlist_locked(exec_ctx, glb_policy->serverlist); // Replace the LB addresses in the channel args that we pass down to // the subchannel. static const char *keys_to_remove[] = {GRPC_ARG_LB_ADDRESSES}; @@ -727,7 +723,6 @@ static void create_rr_locked(grpc_exec_ctx *exec_ctx, glb_lb_policy *glb_policy, /* Connectivity state is a function of the RR policy updated/created */ update_lb_connectivity_status_locked(exec_ctx, glb_policy, rr_state, rr_state_error); - /* Add the gRPC LB's interested_parties pollset_set to that of the newly * created RR policy. This will make the RR policy progress upon activity on * gRPC LB, which in turn is tied to the application's call */ @@ -761,8 +756,8 @@ static void create_rr_locked(grpc_exec_ctx *exec_ctx, glb_lb_policy *glb_policy, pp->wrapped_on_complete_arg.client_stats = grpc_grpclb_client_stats_ref(glb_policy->client_stats); if (GRPC_TRACER_ON(grpc_lb_glb_trace)) { - gpr_log(GPR_INFO, "Pending pick about to PICK from 0x%" PRIxPTR "", - (intptr_t)glb_policy->rr_policy); + gpr_log(GPR_INFO, "Pending pick about to (async) PICK from %p", + (void *)glb_policy->rr_policy); } pick_from_internal_rr_locked(exec_ctx, glb_policy, &pp->pick_args, true /* force_async */, pp->target, @@ -788,10 +783,9 @@ static void rr_handover_locked(grpc_exec_ctx *exec_ctx, glb_lb_policy *glb_policy) { GPR_ASSERT(glb_policy->serverlist != NULL && glb_policy->serverlist->num_servers > 0); - if (glb_policy->shutting_down) return; - grpc_lb_policy_args *args = lb_policy_args_create(exec_ctx, glb_policy); + GPR_ASSERT(args != NULL); if (glb_policy->rr_policy != NULL) { if (GRPC_TRACER_ON(grpc_lb_glb_trace)) { gpr_log(GPR_DEBUG, "Updating Round Robin policy (%p)", @@ -826,8 +820,8 @@ static void glb_rr_connectivity_changed_locked(grpc_exec_ctx *exec_ctx, unref_needed = true; gpr_free(rr_connectivity); } else { /* rr state != SHUTDOWN && !shutting down: biz as usual */ - update_lb_connectivity_status_locked(exec_ctx, glb_policy, - rr_connectivity->state, error); + update_lb_connectivity_status_locked( + exec_ctx, glb_policy, rr_connectivity->state, GRPC_ERROR_REF(error)); /* Resubscribe. Reuse the "rr_connectivity_cb" weak ref. */ grpc_lb_policy_notify_on_state_change_locked( exec_ctx, glb_policy->rr_policy, &rr_connectivity->state, @@ -1089,6 +1083,16 @@ static void glb_shutdown_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { } } +// Cancel a specific pending pick. +// +// A grpclb pick progresses as follows: +// - If there's a Round Robin policy (glb_policy->rr_policy) available, it'll be +// handed over to the RR policy (in create_rr_locked()). From that point +// onwards, it'll be RR's responsibility. For cancellations, that implies the +// pick needs also be cancelled by the RR instance. +// - Otherwise, without an RR instance, picks stay pending at this policy's +// level (grpclb), inside the glb_policy->pending_picks list. To cancel these, +// we invoke the completion closure and set *target to NULL right here. static void glb_cancel_pick_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, grpc_connected_subchannel **target, grpc_error *error) { @@ -1108,9 +1112,23 @@ static void glb_cancel_pick_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, } pp = next; } + if (glb_policy->rr_policy != NULL) { + grpc_lb_policy_cancel_pick_locked(exec_ctx, glb_policy->rr_policy, target, + GRPC_ERROR_REF(error)); + } GRPC_ERROR_UNREF(error); } +// Cancel all pending picks. +// +// A grpclb pick progresses as follows: +// - If there's a Round Robin policy (glb_policy->rr_policy) available, it'll be +// handed over to the RR policy (in create_rr_locked()). From that point +// onwards, it'll be RR's responsibility. For cancellations, that implies the +// pick needs also be cancelled by the RR instance. +// - Otherwise, without an RR instance, picks stay pending at this policy's +// level (grpclb), inside the glb_policy->pending_picks list. To cancel these, +// we invoke the completion closure and set *target to NULL right here. static void glb_cancel_picks_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, uint32_t initial_metadata_flags_mask, @@ -1132,6 +1150,11 @@ static void glb_cancel_picks_locked(grpc_exec_ctx *exec_ctx, } pp = next; } + if (glb_policy->rr_policy != NULL) { + grpc_lb_policy_cancel_picks_locked( + exec_ctx, glb_policy->rr_policy, initial_metadata_flags_mask, + initial_metadata_flags_eq, GRPC_ERROR_REF(error)); + } GRPC_ERROR_UNREF(error); } @@ -1463,7 +1486,8 @@ static void query_for_backends_locked(grpc_exec_ctx *exec_ctx, op++; /* take a weak ref (won't prevent calling of \a glb_shutdown if the strong ref * count goes to zero) to be unref'd in lb_on_sent_initial_request_locked() */ - GRPC_LB_POLICY_WEAK_REF(&glb_policy->base, "lb_on_server_status_received"); + GRPC_LB_POLICY_WEAK_REF(&glb_policy->base, + "lb_on_sent_initial_request_locked"); call_error = grpc_call_start_batch_and_execute( exec_ctx, glb_policy->lb_call, ops, (size_t)(op - ops), &glb_policy->lb_on_sent_initial_request); @@ -1480,8 +1504,9 @@ static void query_for_backends_locked(grpc_exec_ctx *exec_ctx, op->reserved = NULL; op++; /* take a weak ref (won't prevent calling of \a glb_shutdown if the strong ref - * count goes to zero) to be unref'd in lb_on_server_status_received */ - GRPC_LB_POLICY_WEAK_REF(&glb_policy->base, "lb_on_server_status_received"); + * count goes to zero) to be unref'd in lb_on_server_status_received_locked */ + GRPC_LB_POLICY_WEAK_REF(&glb_policy->base, + "lb_on_server_status_received_locked"); call_error = grpc_call_start_batch_and_execute( exec_ctx, glb_policy->lb_call, ops, (size_t)(op - ops), &glb_policy->lb_on_server_status_received); @@ -1493,8 +1518,9 @@ static void query_for_backends_locked(grpc_exec_ctx *exec_ctx, op->flags = 0; op->reserved = NULL; op++; - /* take another weak ref to be unref'd in lb_on_response_received */ - GRPC_LB_POLICY_WEAK_REF(&glb_policy->base, "lb_on_response_received"); + /* take another weak ref to be unref'd/reused in + * lb_on_response_received_locked */ + GRPC_LB_POLICY_WEAK_REF(&glb_policy->base, "lb_on_response_received_locked"); call_error = grpc_call_start_batch_and_execute( exec_ctx, glb_policy->lb_call, ops, (size_t)(op - ops), &glb_policy->lb_on_response_received); @@ -1511,13 +1537,12 @@ static void lb_on_sent_initial_request_locked(grpc_exec_ctx *exec_ctx, do_send_client_load_report_locked(exec_ctx, glb_policy); } GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &glb_policy->base, - "lb_on_response_received_locked"); + "lb_on_sent_initial_request_locked"); } static void lb_on_response_received_locked(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { glb_lb_policy *glb_policy = arg; - grpc_op ops[2]; memset(ops, 0, sizeof(ops)); grpc_op *op = ops; @@ -1548,7 +1573,7 @@ static void lb_on_response_received_locked(grpc_exec_ctx *exec_ctx, void *arg, } /* take a weak ref (won't prevent calling of \a glb_shutdown() if the * strong ref count goes to zero) to be unref'd in - * send_client_load_report() */ + * send_client_load_report_locked() */ glb_policy->client_load_report_timer_pending = true; GRPC_LB_POLICY_WEAK_REF(&glb_policy->base, "client_load_report"); schedule_next_client_load_report(exec_ctx, glb_policy); @@ -1576,7 +1601,6 @@ static void lb_on_response_received_locked(grpc_exec_ctx *exec_ctx, void *arg, gpr_free(ipport); } } - /* update serverlist */ if (serverlist->num_servers > 0) { if (grpc_grpclb_serverlist_equals(glb_policy->serverlist, @@ -1611,9 +1635,7 @@ static void lb_on_response_received_locked(grpc_exec_ctx *exec_ctx, void *arg, grpc_dump_slice(response_slice, GPR_DUMP_ASCII | GPR_DUMP_HEX)); } } - grpc_slice_unref_internal(exec_ctx, response_slice); - if (!glb_policy->shutting_down) { /* keep listening for serverlist updates */ op->op = GRPC_OP_RECV_MESSAGE; @@ -1621,7 +1643,7 @@ static void lb_on_response_received_locked(grpc_exec_ctx *exec_ctx, void *arg, op->flags = 0; op->reserved = NULL; op++; - /* reuse the "lb_on_response_received" weak ref taken in + /* reuse the "lb_on_response_received_locked" weak ref taken in * query_for_backends_locked() */ const grpc_call_error call_error = grpc_call_start_batch_and_execute( exec_ctx, glb_policy->lb_call, ops, (size_t)(op - ops), @@ -1629,10 +1651,10 @@ static void lb_on_response_received_locked(grpc_exec_ctx *exec_ctx, void *arg, GPR_ASSERT(GRPC_CALL_OK == call_error); } } else { /* empty payload: call cancelled. */ - /* dispose of the "lb_on_response_received" weak ref taken in + /* dispose of the "lb_on_response_received_locked" weak ref taken in * query_for_backends_locked() and reused in every reception loop */ GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &glb_policy->base, - "lb_on_response_received_empty_payload"); + "lb_on_response_received_locked_empty_payload"); } } @@ -1699,7 +1721,7 @@ static void lb_on_server_status_received_locked(grpc_exec_ctx *exec_ctx, &glb_policy->lb_on_call_retry, now); } GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &glb_policy->base, - "lb_on_server_status_received"); + "lb_on_server_status_received_locked"); } static void glb_update_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, diff --git a/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.c b/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.c index 341763a4d71..bc40165cfb8 100644 --- a/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.c +++ b/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.c @@ -584,10 +584,16 @@ static void rr_connectivity_changed_locked(grpc_exec_ctx *exec_ctx, void *arg, // Dispose of outdated subchannel lists. if (sd->subchannel_list != p->subchannel_list && sd->subchannel_list != p->latest_pending_subchannel_list) { - // sd belongs to an outdated subchannel_list: get rid of it. - rr_subchannel_list_shutdown_and_unref(exec_ctx, sd->subchannel_list, - "sl_outdated"); - GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "sl_outdated"); + char *reason = NULL; + if (sd->subchannel_list->shutting_down) { + reason = "sl_outdated_straggler"; + rr_subchannel_list_unref(exec_ctx, sd->subchannel_list, reason); + } else { + reason = "sl_outdated"; + rr_subchannel_list_shutdown_and_unref(exec_ctx, sd->subchannel_list, + reason); + } + GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, reason); return; } // Now that we're inside the combiner, copy the pending connectivity @@ -753,6 +759,7 @@ static void rr_update_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, for (size_t i = 0; i < addresses->num_addresses; i++) { if (!addresses->addresses[i].is_balancer) ++num_addrs; } + rr_subchannel_list *subchannel_list = rr_subchannel_list_create(p, num_addrs); if (num_addrs == 0) { grpc_connectivity_state_set( exec_ctx, &p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE, @@ -761,18 +768,16 @@ static void rr_update_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, if (p->subchannel_list != NULL) { rr_subchannel_list_shutdown_and_unref(exec_ctx, p->subchannel_list, "sl_shutdown_empty_update"); - p->subchannel_list = NULL; } + p->subchannel_list = subchannel_list; // empty list return; } size_t subchannel_index = 0; - rr_subchannel_list *subchannel_list = rr_subchannel_list_create(p, num_addrs); if (p->latest_pending_subchannel_list != NULL && p->started_picking) { if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) { gpr_log(GPR_DEBUG, "[RR %p] Shutting down latest pending subchannel list %p, about " - "to be " - "replaced by newer latest %p", + "to be replaced by newer latest %p", (void *)p, (void *)p->latest_pending_subchannel_list, (void *)subchannel_list); } @@ -876,10 +881,10 @@ static grpc_lb_policy *round_robin_create(grpc_exec_ctx *exec_ctx, grpc_lb_policy_args *args) { GPR_ASSERT(args->client_channel_factory != NULL); round_robin_lb_policy *p = gpr_zalloc(sizeof(*p)); - rr_update_locked(exec_ctx, &p->base, args); grpc_lb_policy_init(&p->base, &round_robin_lb_policy_vtable, args->combiner); grpc_connectivity_state_init(&p->state_tracker, GRPC_CHANNEL_IDLE, "round_robin"); + rr_update_locked(exec_ctx, &p->base, args); if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) { gpr_log(GPR_DEBUG, "[RR %p] Created with %lu subchannels", (void *)p, (unsigned long)p->subchannel_list->num_subchannels); diff --git a/test/cpp/end2end/grpclb_end2end_test.cc b/test/cpp/end2end/grpclb_end2end_test.cc index 86cce2d30d4..1f3255d18d8 100644 --- a/test/cpp/end2end/grpclb_end2end_test.cc +++ b/test/cpp/end2end/grpclb_end2end_test.cc @@ -73,8 +73,8 @@ extern "C" { using std::chrono::system_clock; -using grpc::lb::v1::LoadBalanceResponse; using grpc::lb::v1::LoadBalanceRequest; +using grpc::lb::v1::LoadBalanceResponse; using grpc::lb::v1::LoadBalancer; namespace grpc { @@ -647,7 +647,6 @@ class UpdatesTest : public GrpclbEnd2endTest { TEST_F(UpdatesTest, UpdateBalancers) { const std::vector first_backend{GetBackendPorts()[0]}; const std::vector second_backend{GetBackendPorts()[1]}; - ScheduleResponseForBalancer( 0, BalancerServiceImpl::BuildResponseForBackends(first_backend, 0, 0), 0); ScheduleResponseForBalancer( @@ -934,6 +933,45 @@ TEST_F(SingleBalancerTest, Drop) { EXPECT_EQ(1U, balancer_servers_[0].service_->response_count()); } +TEST_F(SingleBalancerTest, DropAllFirst) { + // All registered addresses are marked as "drop". + ScheduleResponseForBalancer( + 0, BalancerServiceImpl::BuildResponseForBackends({}, 1, 1), 0); + const auto& statuses_and_responses = SendRpc(kMessage_, 1); + for (const auto& status_and_response : statuses_and_responses) { + const Status& status = status_and_response.first; + EXPECT_FALSE(status.ok()); + EXPECT_EQ(status.error_message(), "Call dropped by load balancing policy"); + } +} + +TEST_F(SingleBalancerTest, DropAll) { + ScheduleResponseForBalancer( + 0, BalancerServiceImpl::BuildResponseForBackends(GetBackendPorts(), 0, 0), + 0); + ScheduleResponseForBalancer( + 0, BalancerServiceImpl::BuildResponseForBackends({}, 1, 1), 1000); + + // First call succeeds. + auto statuses_and_responses = SendRpc(kMessage_, 1); + for (const auto& status_and_response : statuses_and_responses) { + const Status& status = status_and_response.first; + const EchoResponse& response = status_and_response.second; + EXPECT_TRUE(status.ok()) << "code=" << status.error_code() + << " message=" << status.error_message(); + EXPECT_EQ(response.message(), kMessage_); + } + // But eventually, the update with only dropped servers is processed and calls + // fail. + do { + statuses_and_responses = SendRpc(kMessage_, 1); + ASSERT_EQ(statuses_and_responses.size(), 1UL); + } while (statuses_and_responses[0].first.ok()); + const Status& status = statuses_and_responses[0].first; + EXPECT_FALSE(status.ok()); + EXPECT_EQ(status.error_message(), "Call dropped by load balancing policy"); +} + class SingleBalancerWithClientLoadReportingTest : public GrpclbEnd2endTest { public: SingleBalancerWithClientLoadReportingTest() : GrpclbEnd2endTest(4, 1, 2) {} From b7a7301cb8c1413438a9d6a40f06ca4997e4fef6 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Tue, 25 Jul 2017 16:13:42 +0200 Subject: [PATCH 102/127] add script to generate index.html report --- .../helper_scripts/gen_report_index.sh | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100755 tools/internal_ci/helper_scripts/gen_report_index.sh diff --git a/tools/internal_ci/helper_scripts/gen_report_index.sh b/tools/internal_ci/helper_scripts/gen_report_index.sh new file mode 100755 index 00000000000..cda2fa92a67 --- /dev/null +++ b/tools/internal_ci/helper_scripts/gen_report_index.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash +# Copyright 2017 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Generates index.html that will contain links to various test results on kokoro. +set -e + +# change to grpc repo root +cd $(dirname $0)/../../.. + +# Jenkins URLs are in form "grpc/job/macos/job/experimental/job/jtattermusch_experiment" +KOKORO_JOB_PATH=$(echo "${KOKORO_JOB_NAME}" | sed "s|/|/job/|g") + +mkdir -p reports + +echo '' > reports/kokoro_index.html +echo '

'${KOKORO_JOB_NAME}', build '#${KOKORO_BUILD_NUMBER}'

' >> reports/kokoro_index.html +echo '

Kokoro build dashboard (internal only)

' >> reports/kokoro_index.html +echo '

Test result dashboard (internal only)

' >> reports/kokoro_index.html +echo '

HTML test report (Not available yet)

' >> reports/kokoro_index.html +echo '

Test log (Not available yet)

' >> reports/kokoro_index.html +echo '' >> reports/kokoro_index.html + +echo 'Created reports/kokoro_index.html report index' From 3b091ee059d4c351be6d786954e8a6d6ba03a257 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Wed, 26 Jul 2017 10:49:52 +0200 Subject: [PATCH 103/127] upload reports as artifacts --- tools/internal_ci/helper_scripts/prepare_build_linux_rc | 2 ++ tools/internal_ci/helper_scripts/prepare_build_macos_rc | 2 ++ tools/internal_ci/linux/grpc_basictests_c_cpp_dbg.cfg | 1 + tools/internal_ci/linux/grpc_basictests_c_cpp_opt.cfg | 1 + tools/internal_ci/linux/grpc_basictests_multilang.cfg | 1 + tools/internal_ci/linux/grpc_build_artifacts.cfg | 1 + tools/internal_ci/linux/grpc_interop_badserver_java.cfg | 2 +- tools/internal_ci/linux/grpc_interop_badserver_python.cfg | 2 +- tools/internal_ci/linux/grpc_interop_matrix.cfg | 1 + tools/internal_ci/linux/grpc_interop_tocloud.cfg | 1 + tools/internal_ci/linux/grpc_interop_toprod.cfg | 1 + tools/internal_ci/linux/grpc_master.cfg | 1 + tools/internal_ci/linux/grpc_portability.cfg | 1 + tools/internal_ci/linux/grpc_portability_build_only.cfg | 1 + tools/internal_ci/linux/grpc_pull_request_sanity.cfg | 1 + tools/internal_ci/linux/grpc_sanity.cfg | 1 + tools/internal_ci/linux/sanitizer/grpc_c_asan.cfg | 1 + tools/internal_ci/linux/sanitizer/grpc_c_msan.cfg | 1 + tools/internal_ci/linux/sanitizer/grpc_c_tsan.cfg | 1 + tools/internal_ci/linux/sanitizer/grpc_c_ubsan.cfg | 1 + tools/internal_ci/linux/sanitizer/grpc_cpp_asan.cfg | 1 + tools/internal_ci/linux/sanitizer/grpc_cpp_tsan.cfg | 1 + tools/internal_ci/linux/sanitizer/pull_request/grpc_c_asan.cfg | 1 + tools/internal_ci/linux/sanitizer/pull_request/grpc_c_msan.cfg | 1 + tools/internal_ci/linux/sanitizer/pull_request/grpc_c_tsan.cfg | 1 + tools/internal_ci/linux/sanitizer/pull_request/grpc_c_ubsan.cfg | 1 + .../internal_ci/linux/sanitizer/pull_request/grpc_cpp_asan.cfg | 1 + .../internal_ci/linux/sanitizer/pull_request/grpc_cpp_tsan.cfg | 1 + tools/internal_ci/macos/grpc_build_artifacts.cfg | 1 + tools/internal_ci/macos/grpc_interop.cfg | 2 +- tools/internal_ci/macos/grpc_master.cfg | 1 + tools/internal_ci/windows/grpc_build_artifacts.cfg | 1 + tools/internal_ci/windows/grpc_master.cfg | 1 + tools/internal_ci/windows/grpc_portability_master.cfg | 1 + 34 files changed, 36 insertions(+), 3 deletions(-) diff --git a/tools/internal_ci/helper_scripts/prepare_build_linux_rc b/tools/internal_ci/helper_scripts/prepare_build_linux_rc index 7b7db19389f..049db33ec36 100644 --- a/tools/internal_ci/helper_scripts/prepare_build_linux_rc +++ b/tools/internal_ci/helper_scripts/prepare_build_linux_rc @@ -15,6 +15,8 @@ # Source this rc script to prepare the environment for linux builds +tools/internal_ci/helper_scripts/gen_report_index.sh + # Need to increase open files limit for c tests ulimit -n 32768 diff --git a/tools/internal_ci/helper_scripts/prepare_build_macos_rc b/tools/internal_ci/helper_scripts/prepare_build_macos_rc index 57463e6f6de..89e8e24351c 100644 --- a/tools/internal_ci/helper_scripts/prepare_build_macos_rc +++ b/tools/internal_ci/helper_scripts/prepare_build_macos_rc @@ -15,6 +15,8 @@ # Source this rc script to prepare the environment for macos builds +tools/internal_ci/helper_scripts/gen_report_index.sh + sudo launchctl limit maxfiles unlimited unlimited # show current maxfiles diff --git a/tools/internal_ci/linux/grpc_basictests_c_cpp_dbg.cfg b/tools/internal_ci/linux/grpc_basictests_c_cpp_dbg.cfg index ca547a0a4f7..4a0badf43bc 100644 --- a/tools/internal_ci/linux/grpc_basictests_c_cpp_dbg.cfg +++ b/tools/internal_ci/linux/grpc_basictests_c_cpp_dbg.cfg @@ -20,6 +20,7 @@ timeout_mins: 240 action { define_artifacts { regex: "**/*sponge_log.xml" + regex: "github/grpc/reports/**" } } diff --git a/tools/internal_ci/linux/grpc_basictests_c_cpp_opt.cfg b/tools/internal_ci/linux/grpc_basictests_c_cpp_opt.cfg index 62f05cef2ef..a2cfe021e16 100644 --- a/tools/internal_ci/linux/grpc_basictests_c_cpp_opt.cfg +++ b/tools/internal_ci/linux/grpc_basictests_c_cpp_opt.cfg @@ -20,6 +20,7 @@ timeout_mins: 240 action { define_artifacts { regex: "**/*sponge_log.xml" + regex: "github/grpc/reports/**" } } diff --git a/tools/internal_ci/linux/grpc_basictests_multilang.cfg b/tools/internal_ci/linux/grpc_basictests_multilang.cfg index be099d78c70..4433d14cd72 100644 --- a/tools/internal_ci/linux/grpc_basictests_multilang.cfg +++ b/tools/internal_ci/linux/grpc_basictests_multilang.cfg @@ -20,6 +20,7 @@ timeout_mins: 240 action { define_artifacts { regex: "**/*sponge_log.xml" + regex: "github/grpc/reports/**" } } diff --git a/tools/internal_ci/linux/grpc_build_artifacts.cfg b/tools/internal_ci/linux/grpc_build_artifacts.cfg index eb37b5b0cd6..88fc6b7b358 100644 --- a/tools/internal_ci/linux/grpc_build_artifacts.cfg +++ b/tools/internal_ci/linux/grpc_build_artifacts.cfg @@ -20,6 +20,7 @@ timeout_mins: 120 action { define_artifacts { regex: "**/*sponge_log.xml" + regex: "github/grpc/reports/**" regex: "github/grpc/artifacts/**" } } diff --git a/tools/internal_ci/linux/grpc_interop_badserver_java.cfg b/tools/internal_ci/linux/grpc_interop_badserver_java.cfg index 0aadb56c7c8..dc2114273ea 100644 --- a/tools/internal_ci/linux/grpc_interop_badserver_java.cfg +++ b/tools/internal_ci/linux/grpc_interop_badserver_java.cfg @@ -20,7 +20,7 @@ build_file: "grpc/tools/internal_ci/linux/grpc_interop_badserver_java.sh" timeout_mins: 480 action { define_artifacts { - regex: "**/report.xml", + regex: "**/report.xml" regex: "github/grpc/reports/**" } } diff --git a/tools/internal_ci/linux/grpc_interop_badserver_python.cfg b/tools/internal_ci/linux/grpc_interop_badserver_python.cfg index 29c5c635f9a..ec738fcf74a 100644 --- a/tools/internal_ci/linux/grpc_interop_badserver_python.cfg +++ b/tools/internal_ci/linux/grpc_interop_badserver_python.cfg @@ -20,7 +20,7 @@ build_file: "grpc/tools/internal_ci/linux/grpc_interop_badserver_python.sh" timeout_mins: 480 action { define_artifacts { - regex: "**/report.xml", + regex: "**/report.xml" regex: "github/grpc/reports/**" } } diff --git a/tools/internal_ci/linux/grpc_interop_matrix.cfg b/tools/internal_ci/linux/grpc_interop_matrix.cfg index 2fa3e8f897c..a7fd479a734 100644 --- a/tools/internal_ci/linux/grpc_interop_matrix.cfg +++ b/tools/internal_ci/linux/grpc_interop_matrix.cfg @@ -21,5 +21,6 @@ timeout_mins: 60 action { define_artifacts { regex: "**/sponge_log.xml" + regex: "github/grpc/reports/**" } } diff --git a/tools/internal_ci/linux/grpc_interop_tocloud.cfg b/tools/internal_ci/linux/grpc_interop_tocloud.cfg index 0c31b497afe..c613f668d97 100644 --- a/tools/internal_ci/linux/grpc_interop_tocloud.cfg +++ b/tools/internal_ci/linux/grpc_interop_tocloud.cfg @@ -21,5 +21,6 @@ timeout_mins: 480 action { define_artifacts { regex: "**/sponge_log.xml" + regex: "github/grpc/reports/**" } } diff --git a/tools/internal_ci/linux/grpc_interop_toprod.cfg b/tools/internal_ci/linux/grpc_interop_toprod.cfg index 18978b87e55..903480a3d18 100644 --- a/tools/internal_ci/linux/grpc_interop_toprod.cfg +++ b/tools/internal_ci/linux/grpc_interop_toprod.cfg @@ -21,6 +21,7 @@ timeout_mins: 60 action { define_artifacts { regex: "**/sponge_log.xml" + regex: "github/grpc/reports/**" } } diff --git a/tools/internal_ci/linux/grpc_master.cfg b/tools/internal_ci/linux/grpc_master.cfg index 8bcc668ba97..a2784df2974 100644 --- a/tools/internal_ci/linux/grpc_master.cfg +++ b/tools/internal_ci/linux/grpc_master.cfg @@ -20,6 +20,7 @@ timeout_mins: 240 action { define_artifacts { regex: "**/*sponge_log.xml" + regex: "github/grpc/reports/**" } } diff --git a/tools/internal_ci/linux/grpc_portability.cfg b/tools/internal_ci/linux/grpc_portability.cfg index c5bfd3bb40b..8c120be6b9a 100644 --- a/tools/internal_ci/linux/grpc_portability.cfg +++ b/tools/internal_ci/linux/grpc_portability.cfg @@ -20,6 +20,7 @@ timeout_mins: 1440 action { define_artifacts { regex: "**/*sponge_log.xml" + regex: "github/grpc/reports/**" } } diff --git a/tools/internal_ci/linux/grpc_portability_build_only.cfg b/tools/internal_ci/linux/grpc_portability_build_only.cfg index fce914c6121..501223c0c73 100644 --- a/tools/internal_ci/linux/grpc_portability_build_only.cfg +++ b/tools/internal_ci/linux/grpc_portability_build_only.cfg @@ -20,6 +20,7 @@ timeout_mins: 180 action { define_artifacts { regex: "**/*sponge_log.xml" + regex: "github/grpc/reports/**" } } diff --git a/tools/internal_ci/linux/grpc_pull_request_sanity.cfg b/tools/internal_ci/linux/grpc_pull_request_sanity.cfg index 6c76a929c04..b20d2ffba8e 100644 --- a/tools/internal_ci/linux/grpc_pull_request_sanity.cfg +++ b/tools/internal_ci/linux/grpc_pull_request_sanity.cfg @@ -20,6 +20,7 @@ timeout_mins: 30 action { define_artifacts { regex: "**/*sponge_log.xml" + regex: "github/grpc/reports/**" } } diff --git a/tools/internal_ci/linux/grpc_sanity.cfg b/tools/internal_ci/linux/grpc_sanity.cfg index 8dfeda0d456..24e7984f3a5 100644 --- a/tools/internal_ci/linux/grpc_sanity.cfg +++ b/tools/internal_ci/linux/grpc_sanity.cfg @@ -20,6 +20,7 @@ timeout_mins: 20 action { define_artifacts { regex: "**/*sponge_log.xml" + regex: "github/grpc/reports/**" } } diff --git a/tools/internal_ci/linux/sanitizer/grpc_c_asan.cfg b/tools/internal_ci/linux/sanitizer/grpc_c_asan.cfg index c4beaacf6bb..06a4372ce24 100644 --- a/tools/internal_ci/linux/sanitizer/grpc_c_asan.cfg +++ b/tools/internal_ci/linux/sanitizer/grpc_c_asan.cfg @@ -20,6 +20,7 @@ timeout_mins: 1440 action { define_artifacts { regex: "**/*sponge_log.xml" + regex: "github/grpc/reports/**" } } diff --git a/tools/internal_ci/linux/sanitizer/grpc_c_msan.cfg b/tools/internal_ci/linux/sanitizer/grpc_c_msan.cfg index 0197966f32f..f875327c1b8 100644 --- a/tools/internal_ci/linux/sanitizer/grpc_c_msan.cfg +++ b/tools/internal_ci/linux/sanitizer/grpc_c_msan.cfg @@ -20,6 +20,7 @@ timeout_mins: 1440 action { define_artifacts { regex: "**/*sponge_log.xml" + regex: "github/grpc/reports/**" } } diff --git a/tools/internal_ci/linux/sanitizer/grpc_c_tsan.cfg b/tools/internal_ci/linux/sanitizer/grpc_c_tsan.cfg index 243eb99fbbb..6658a804d89 100644 --- a/tools/internal_ci/linux/sanitizer/grpc_c_tsan.cfg +++ b/tools/internal_ci/linux/sanitizer/grpc_c_tsan.cfg @@ -20,6 +20,7 @@ timeout_mins: 1440 action { define_artifacts { regex: "**/*sponge_log.xml" + regex: "github/grpc/reports/**" } } diff --git a/tools/internal_ci/linux/sanitizer/grpc_c_ubsan.cfg b/tools/internal_ci/linux/sanitizer/grpc_c_ubsan.cfg index 24c7bf8a4c9..957a91ef2b4 100644 --- a/tools/internal_ci/linux/sanitizer/grpc_c_ubsan.cfg +++ b/tools/internal_ci/linux/sanitizer/grpc_c_ubsan.cfg @@ -20,6 +20,7 @@ timeout_mins: 1440 action { define_artifacts { regex: "**/*sponge_log.xml" + regex: "github/grpc/reports/**" } } diff --git a/tools/internal_ci/linux/sanitizer/grpc_cpp_asan.cfg b/tools/internal_ci/linux/sanitizer/grpc_cpp_asan.cfg index f12366cb0a7..dbbfce90cb5 100644 --- a/tools/internal_ci/linux/sanitizer/grpc_cpp_asan.cfg +++ b/tools/internal_ci/linux/sanitizer/grpc_cpp_asan.cfg @@ -20,6 +20,7 @@ timeout_mins: 1440 action { define_artifacts { regex: "**/*sponge_log.xml" + regex: "github/grpc/reports/**" } } diff --git a/tools/internal_ci/linux/sanitizer/grpc_cpp_tsan.cfg b/tools/internal_ci/linux/sanitizer/grpc_cpp_tsan.cfg index ca807aed163..fb0cefa1606 100644 --- a/tools/internal_ci/linux/sanitizer/grpc_cpp_tsan.cfg +++ b/tools/internal_ci/linux/sanitizer/grpc_cpp_tsan.cfg @@ -20,6 +20,7 @@ timeout_mins: 1440 action { define_artifacts { regex: "**/*sponge_log.xml" + regex: "github/grpc/reports/**" } } diff --git a/tools/internal_ci/linux/sanitizer/pull_request/grpc_c_asan.cfg b/tools/internal_ci/linux/sanitizer/pull_request/grpc_c_asan.cfg index 98eb4d0139d..649d93d0a12 100644 --- a/tools/internal_ci/linux/sanitizer/pull_request/grpc_c_asan.cfg +++ b/tools/internal_ci/linux/sanitizer/pull_request/grpc_c_asan.cfg @@ -21,6 +21,7 @@ timeout_mins: 1440 action { define_artifacts { regex: "**/*sponge_log.xml" + regex: "github/grpc/reports/**" } } diff --git a/tools/internal_ci/linux/sanitizer/pull_request/grpc_c_msan.cfg b/tools/internal_ci/linux/sanitizer/pull_request/grpc_c_msan.cfg index e47762ca885..d5ba2031fcb 100644 --- a/tools/internal_ci/linux/sanitizer/pull_request/grpc_c_msan.cfg +++ b/tools/internal_ci/linux/sanitizer/pull_request/grpc_c_msan.cfg @@ -21,6 +21,7 @@ timeout_mins: 1440 action { define_artifacts { regex: "**/*sponge_log.xml" + regex: "github/grpc/reports/**" } } diff --git a/tools/internal_ci/linux/sanitizer/pull_request/grpc_c_tsan.cfg b/tools/internal_ci/linux/sanitizer/pull_request/grpc_c_tsan.cfg index c3803aff563..67d4356821a 100644 --- a/tools/internal_ci/linux/sanitizer/pull_request/grpc_c_tsan.cfg +++ b/tools/internal_ci/linux/sanitizer/pull_request/grpc_c_tsan.cfg @@ -21,6 +21,7 @@ timeout_mins: 1440 action { define_artifacts { regex: "**/*sponge_log.xml" + regex: "github/grpc/reports/**" } } diff --git a/tools/internal_ci/linux/sanitizer/pull_request/grpc_c_ubsan.cfg b/tools/internal_ci/linux/sanitizer/pull_request/grpc_c_ubsan.cfg index 831cfb53ba4..c162d1d1d05 100644 --- a/tools/internal_ci/linux/sanitizer/pull_request/grpc_c_ubsan.cfg +++ b/tools/internal_ci/linux/sanitizer/pull_request/grpc_c_ubsan.cfg @@ -21,6 +21,7 @@ timeout_mins: 1440 action { define_artifacts { regex: "**/*sponge_log.xml" + regex: "github/grpc/reports/**" } } diff --git a/tools/internal_ci/linux/sanitizer/pull_request/grpc_cpp_asan.cfg b/tools/internal_ci/linux/sanitizer/pull_request/grpc_cpp_asan.cfg index c3324431822..29f1fce5684 100644 --- a/tools/internal_ci/linux/sanitizer/pull_request/grpc_cpp_asan.cfg +++ b/tools/internal_ci/linux/sanitizer/pull_request/grpc_cpp_asan.cfg @@ -21,6 +21,7 @@ timeout_mins: 1440 action { define_artifacts { regex: "**/*sponge_log.xml" + regex: "github/grpc/reports/**" } } diff --git a/tools/internal_ci/linux/sanitizer/pull_request/grpc_cpp_tsan.cfg b/tools/internal_ci/linux/sanitizer/pull_request/grpc_cpp_tsan.cfg index 92cd93fcac8..331f73b3c7f 100644 --- a/tools/internal_ci/linux/sanitizer/pull_request/grpc_cpp_tsan.cfg +++ b/tools/internal_ci/linux/sanitizer/pull_request/grpc_cpp_tsan.cfg @@ -21,6 +21,7 @@ timeout_mins: 1440 action { define_artifacts { regex: "**/*sponge_log.xml" + regex: "github/grpc/reports/**" } } diff --git a/tools/internal_ci/macos/grpc_build_artifacts.cfg b/tools/internal_ci/macos/grpc_build_artifacts.cfg index 19993809478..733933c62a6 100644 --- a/tools/internal_ci/macos/grpc_build_artifacts.cfg +++ b/tools/internal_ci/macos/grpc_build_artifacts.cfg @@ -20,6 +20,7 @@ timeout_mins: 120 action { define_artifacts { regex: "**/*sponge_log.xml" + regex: "github/grpc/reports/**" regex: "github/grpc/artifacts/**" } } diff --git a/tools/internal_ci/macos/grpc_interop.cfg b/tools/internal_ci/macos/grpc_interop.cfg index 25bac2f123d..9f3742c4864 100644 --- a/tools/internal_ci/macos/grpc_interop.cfg +++ b/tools/internal_ci/macos/grpc_interop.cfg @@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/macos/grpc_interop.sh" timeout_mins: 240 action { define_artifacts { - regex: "**/*sponge_log.xml", + regex: "**/*sponge_log.xml" regex: "github/grpc/reports/**" } } diff --git a/tools/internal_ci/macos/grpc_master.cfg b/tools/internal_ci/macos/grpc_master.cfg index 1c34979d012..24c021dfcc2 100644 --- a/tools/internal_ci/macos/grpc_master.cfg +++ b/tools/internal_ci/macos/grpc_master.cfg @@ -20,5 +20,6 @@ timeout_mins: 240 action { define_artifacts { regex: "**/*sponge_log.xml" + regex: "github/grpc/reports/**" } } diff --git a/tools/internal_ci/windows/grpc_build_artifacts.cfg b/tools/internal_ci/windows/grpc_build_artifacts.cfg index da359ca05ae..38b0abd519b 100644 --- a/tools/internal_ci/windows/grpc_build_artifacts.cfg +++ b/tools/internal_ci/windows/grpc_build_artifacts.cfg @@ -20,6 +20,7 @@ timeout_mins: 120 action { define_artifacts { regex: "**/*sponge_log.xml" + regex: "github/grpc/reports/**" regex: "github/grpc/artifacts/**" } } diff --git a/tools/internal_ci/windows/grpc_master.cfg b/tools/internal_ci/windows/grpc_master.cfg index 80abea6c381..786ebc01973 100644 --- a/tools/internal_ci/windows/grpc_master.cfg +++ b/tools/internal_ci/windows/grpc_master.cfg @@ -20,5 +20,6 @@ timeout_mins: 360 action { define_artifacts { regex: "**/*sponge_log.xml" + regex: "github/grpc/reports/**" } } diff --git a/tools/internal_ci/windows/grpc_portability_master.cfg b/tools/internal_ci/windows/grpc_portability_master.cfg index cb48d35de9e..85f69272546 100644 --- a/tools/internal_ci/windows/grpc_portability_master.cfg +++ b/tools/internal_ci/windows/grpc_portability_master.cfg @@ -20,5 +20,6 @@ timeout_mins: 360 action { define_artifacts { regex: "**/*sponge_log.xml" + regex: "github/grpc/reports/**" } } From fa9199581117c4c218220d3ce0bac1457f76e08a Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Wed, 26 Jul 2017 12:14:36 +0200 Subject: [PATCH 104/127] add prepare_build_windows.bat script --- .../helper_scripts/prepare_build_windows.bat | 21 +++++++++++++++++++ .../windows/grpc_build_artifacts.bat | 9 ++------ tools/internal_ci/windows/grpc_master.bat | 6 +----- .../windows/grpc_portability_master.bat | 6 +----- 4 files changed, 25 insertions(+), 17 deletions(-) create mode 100644 tools/internal_ci/helper_scripts/prepare_build_windows.bat diff --git a/tools/internal_ci/helper_scripts/prepare_build_windows.bat b/tools/internal_ci/helper_scripts/prepare_build_windows.bat new file mode 100644 index 00000000000..1634acd389d --- /dev/null +++ b/tools/internal_ci/helper_scripts/prepare_build_windows.bat @@ -0,0 +1,21 @@ +@rem Copyright 2017 gRPC authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem http://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. + +@rem make sure msys binaries are preferred over cygwin binaries +@rem set path to python 2.7 +set PATH=C:\tools\msys64\usr\bin;C:\Python27;%PATH% + +bash tools/internal_ci/helper_scripts/gen_report_index.sh + +git submodule update --init diff --git a/tools/internal_ci/windows/grpc_build_artifacts.bat b/tools/internal_ci/windows/grpc_build_artifacts.bat index 8cfa2fb0bea..29c876dd353 100644 --- a/tools/internal_ci/windows/grpc_build_artifacts.bat +++ b/tools/internal_ci/windows/grpc_build_artifacts.bat @@ -12,7 +12,7 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. -@rem Move python installation from _32bit to _32bits where they are expected python artifact builder +@rem Move python installation from _32bit to _32bits where they are expected by python artifact builder @rem TODO(jtattermusch): get rid of this hack rename C:\Python27_32bit Python27_32bits rename C:\Python34_32bit Python34_32bits @@ -21,15 +21,10 @@ rename C:\Python36_32bit Python36_32bits pacman -S --noconfirm mingw64/mingw-w64-x86_64-gcc mingw32/mingw-w64-i686-gcc -@rem make sure msys binaries are preferred over cygwin binaries -@rem set path to python 2.7 -set PATH=C:\tools\msys64\usr\bin;C:\Python27;%PATH% - - @rem enter repo root cd /d %~dp0\..\..\.. -git submodule update --init +call tools/internal_ci/helper_scripts/prepare_build_windows.bat python tools/run_tests/task_runner.py -f artifact windows || goto :error goto :EOF diff --git a/tools/internal_ci/windows/grpc_master.bat b/tools/internal_ci/windows/grpc_master.bat index 3984b810754..58eefc301bb 100644 --- a/tools/internal_ci/windows/grpc_master.bat +++ b/tools/internal_ci/windows/grpc_master.bat @@ -12,14 +12,10 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. -@rem make sure msys binaries are preferred over cygwin binaries -@rem set path to python 2.7 -set PATH=C:\tools\msys64\usr\bin;C:\Python27;%PATH% - @rem enter repo root cd /d %~dp0\..\..\.. -git submodule update --init +call tools/internal_ci/helper_scripts/prepare_build_windows.bat python tools/run_tests/run_tests_matrix.py -f basictests windows -j 1 --inner_jobs 8 --internal_ci || goto :error goto :EOF diff --git a/tools/internal_ci/windows/grpc_portability_master.bat b/tools/internal_ci/windows/grpc_portability_master.bat index cb6b1fe1337..c93d56c7e4a 100644 --- a/tools/internal_ci/windows/grpc_portability_master.bat +++ b/tools/internal_ci/windows/grpc_portability_master.bat @@ -12,14 +12,10 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. -@rem make sure msys binaries are preferred over cygwin binaries -@rem set path to python 2.7 -set PATH=C:\tools\msys64\usr\bin;C:\Python27;%PATH% - @rem enter repo root cd /d %~dp0\..\..\.. -git submodule update --init +call tools/internal_ci/helper_scripts/prepare_build_windows.bat python tools/run_tests/run_tests_matrix.py -f portability windows -j 1 --inner_jobs 8 --internal_ci || goto :error goto :EOF From 633434aed2b7db1e206c884257b198e04f2bf60e Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Mon, 24 Jul 2017 17:11:35 +0200 Subject: [PATCH 105/127] dont run user handlers on grpc threadpool threads --- .../Grpc.Core.Tests/ThreadingModelTest.cs | 98 +++++++++++++++++++ src/csharp/Grpc.Core/Grpc.Core.csproj | 1 + .../Grpc.Core/Internal/GrpcThreadPool.cs | 19 +++- src/csharp/tests.json | 1 + 4 files changed, 117 insertions(+), 2 deletions(-) create mode 100644 src/csharp/Grpc.Core.Tests/ThreadingModelTest.cs diff --git a/src/csharp/Grpc.Core.Tests/ThreadingModelTest.cs b/src/csharp/Grpc.Core.Tests/ThreadingModelTest.cs new file mode 100644 index 00000000000..fb181989455 --- /dev/null +++ b/src/csharp/Grpc.Core.Tests/ThreadingModelTest.cs @@ -0,0 +1,98 @@ +#region Copyright notice and license + +// Copyright 2015 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#endregion + +using System; +using NUnit.Framework; +using System.Threading; +using System.Threading.Tasks; + +namespace Grpc.Core.Tests +{ + public class ThreadingModelTest + { + const string Host = "127.0.0.1"; + + MockServiceHelper helper; + Server server; + Channel channel; + + [SetUp] + public void Init() + { + helper = new MockServiceHelper(Host); + server = helper.GetServer(); + server.Start(); + channel = helper.GetChannel(); + } + + [TearDown] + public void Cleanup() + { + channel.ShutdownAsync().Wait(); + server.ShutdownAsync().Wait(); + } + + [Test] + public void BlockingCallInServerHandlerDoesNotDeadlock() + { + helper.UnaryHandler = new UnaryServerMethod(async (request, context) => + { + int recursionDepth = int.Parse(request); + if (recursionDepth <= 0) { + return "SUCCESS"; + } + return Calls.BlockingUnaryCall(helper.CreateUnaryCall(), (recursionDepth - 1).ToString()); + }); + + int maxRecursionDepth = Environment.ProcessorCount * 2; // make sure we have more pending blocking calls than threads in GrpcThreadPool + Assert.AreEqual("SUCCESS", Calls.BlockingUnaryCall(helper.CreateUnaryCall(), maxRecursionDepth.ToString())); + } + + [Test] + public void HandlerDoesNotRunOnGrpcThread() + { + helper.UnaryHandler = new UnaryServerMethod(async (request, context) => + { + if (IsRunningOnGrpcThreadPool()) { + return "Server handler should not run on gRPC threadpool thread."; + } + return request; + }); + + Assert.AreEqual("ABC", Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "ABC")); + } + + [Test] + public async Task ContinuationDoesNotRunOnGrpcThread() + { + helper.UnaryHandler = new UnaryServerMethod(async (request, context) => + { + return request; + }); + + await Calls.AsyncUnaryCall(helper.CreateUnaryCall(), "ABC"); + Assert.IsFalse(IsRunningOnGrpcThreadPool()); + } + + private static bool IsRunningOnGrpcThreadPool() + { + var threadName = Thread.CurrentThread.Name ?? ""; + return threadName.Contains("grpc"); + } + } +} diff --git a/src/csharp/Grpc.Core/Grpc.Core.csproj b/src/csharp/Grpc.Core/Grpc.Core.csproj index 50358298f48..e32711c5204 100755 --- a/src/csharp/Grpc.Core/Grpc.Core.csproj +++ b/src/csharp/Grpc.Core/Grpc.Core.csproj @@ -64,6 +64,7 @@ + diff --git a/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs b/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs index f9ae77c74e9..8640058b0cc 100644 --- a/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs +++ b/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs @@ -33,6 +33,8 @@ namespace Grpc.Core.Internal internal class GrpcThreadPool { static readonly ILogger Logger = GrpcEnvironment.Logger.ForType(); + static readonly WaitCallback RunCompletionQueueEventCallbackSuccess = new WaitCallback((callback) => RunCompletionQueueEventCallback((OpCompletionDelegate) callback, true)); + static readonly WaitCallback RunCompletionQueueEventCallbackFailure = new WaitCallback((callback) => RunCompletionQueueEventCallback((OpCompletionDelegate) callback, false)); readonly GrpcEnvironment environment; readonly object myLock = new object(); @@ -165,11 +167,12 @@ namespace Grpc.Core.Internal try { var callback = cq.CompletionRegistry.Extract(tag); - callback(success); + // Use cached delegates to avoid unnecessary allocations + ThreadPool.QueueUserWorkItem(success ? RunCompletionQueueEventCallbackSuccess : RunCompletionQueueEventCallbackFailure, callback); } catch (Exception e) { - Logger.Error(e, "Exception occured while invoking completion delegate"); + Logger.Error(e, "Exception occured while extracting event from completion registry."); } } } @@ -186,5 +189,17 @@ namespace Grpc.Core.Internal } return list.AsReadOnly(); } + + private static void RunCompletionQueueEventCallback(OpCompletionDelegate callback, bool success) + { + try + { + callback(success); + } + catch (Exception e) + { + Logger.Error(e, "Exception occured while invoking completion delegate"); + } + } } } diff --git a/src/csharp/tests.json b/src/csharp/tests.json index bc6adbbfe8b..78410510526 100644 --- a/src/csharp/tests.json +++ b/src/csharp/tests.json @@ -31,6 +31,7 @@ "Grpc.Core.Tests.ShutdownHookPendingCallTest", "Grpc.Core.Tests.ShutdownHookServerTest", "Grpc.Core.Tests.ShutdownTest", + "Grpc.Core.Tests.ThreadingModelTest", "Grpc.Core.Tests.TimeoutsTest", "Grpc.Core.Tests.UserAgentStringTest" ], From 7dbd72497ceee212a33db09c51e0ad3c50a90b7e Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Tue, 25 Jul 2017 14:24:58 +0200 Subject: [PATCH 106/127] introduce inlineHandlers setting --- src/csharp/Grpc.Core/GrpcEnvironment.cs | 22 ++++++++++++++++++- .../Grpc.Core/Internal/GrpcThreadPool.cs | 14 ++++++++++-- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/csharp/Grpc.Core/GrpcEnvironment.cs b/src/csharp/Grpc.Core/GrpcEnvironment.cs index 8d0c66aa5bf..0663ee92150 100644 --- a/src/csharp/Grpc.Core/GrpcEnvironment.cs +++ b/src/csharp/Grpc.Core/GrpcEnvironment.cs @@ -39,6 +39,7 @@ namespace Grpc.Core static int refCount; static int? customThreadPoolSize; static int? customCompletionQueueCount; + static bool inlineHandlers; static readonly HashSet registeredChannels = new HashSet(); static readonly HashSet registeredServers = new HashSet(); @@ -217,13 +218,32 @@ namespace Grpc.Core } } + /// + /// By default, gRPC's internal event handlers get offloaded to .NET default thread pool thread (inlineHandlers=false). + /// Setting inlineHandlers to true will allow scheduling the event handlers directly to + /// GrpcThreadPool internal threads. That can lead to significant performance gains in some situations, + /// but requires user to never block in async code (incorrectly written code can easily lead to deadlocks). + /// Inlining handlers is an advanced setting and you should only use it if you know what you are doing. + /// Most users should rely on the default value provided by gRPC library. + /// Note: this method is part of an experimental API that can change or be removed without any prior notice. + /// Note: inlineHandlers=true was the default in gRPC C# v1.4.x and earlier. + /// + public static void SetHandlerInlining(bool inlineHandlers) + { + lock (staticLock) + { + GrpcPreconditions.CheckState(instance == null, "Can only be set before GrpcEnvironment is initialized"); + GrpcEnvironment.inlineHandlers = inlineHandlers; + } + } + /// /// Creates gRPC environment. /// private GrpcEnvironment() { GrpcNativeInit(); - threadPool = new GrpcThreadPool(this, GetThreadPoolSizeOrDefault(), GetCompletionQueueCountOrDefault()); + threadPool = new GrpcThreadPool(this, GetThreadPoolSizeOrDefault(), GetCompletionQueueCountOrDefault(), inlineHandlers); threadPool.Start(); } diff --git a/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs b/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs index 8640058b0cc..19b44c26189 100644 --- a/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs +++ b/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs @@ -41,6 +41,7 @@ namespace Grpc.Core.Internal readonly List threads = new List(); readonly int poolSize; readonly int completionQueueCount; + readonly bool inlineHandlers; readonly List threadProfilers = new List(); // profilers assigned to threadpool threads @@ -54,11 +55,13 @@ namespace Grpc.Core.Internal /// Environment. /// Pool size. /// Completion queue count. - public GrpcThreadPool(GrpcEnvironment environment, int poolSize, int completionQueueCount) + /// Handler inlining. + public GrpcThreadPool(GrpcEnvironment environment, int poolSize, int completionQueueCount, bool inlineHandlers) { this.environment = environment; this.poolSize = poolSize; this.completionQueueCount = completionQueueCount; + this.inlineHandlers = inlineHandlers; GrpcPreconditions.CheckArgument(poolSize >= completionQueueCount, "Thread pool size cannot be smaller than the number of completion queues used."); } @@ -168,7 +171,14 @@ namespace Grpc.Core.Internal { var callback = cq.CompletionRegistry.Extract(tag); // Use cached delegates to avoid unnecessary allocations - ThreadPool.QueueUserWorkItem(success ? RunCompletionQueueEventCallbackSuccess : RunCompletionQueueEventCallbackFailure, callback); + if (!inlineHandlers) + { + ThreadPool.QueueUserWorkItem(success ? RunCompletionQueueEventCallbackSuccess : RunCompletionQueueEventCallbackFailure, callback); + } + else + { + RunCompletionQueueEventCallback(callback, success); + } } catch (Exception e) { From 75e9eaed4410b54226d113bcb27aff7ba396f2fa Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Tue, 25 Jul 2017 12:23:28 +0200 Subject: [PATCH 107/127] reduce threadpool size for qps benchmarks --- src/csharp/Grpc.IntegrationTesting/QpsWorker.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/csharp/Grpc.IntegrationTesting/QpsWorker.cs b/src/csharp/Grpc.IntegrationTesting/QpsWorker.cs index 7009a93b186..a579fb80406 100644 --- a/src/csharp/Grpc.IntegrationTesting/QpsWorker.cs +++ b/src/csharp/Grpc.IntegrationTesting/QpsWorker.cs @@ -63,11 +63,6 @@ namespace Grpc.IntegrationTesting private async Task RunAsync() { - // (ThreadPoolSize == ProcessorCount) gives best throughput in benchmarks - // and doesn't seem to harm performance even when server and client - // are running on the same machine. - GrpcEnvironment.SetThreadPoolSize(Environment.ProcessorCount); - string host = "0.0.0.0"; int port = options.DriverPort; From 4095cd9de4d10d2b05363fb40f9a9cd669999591 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Wed, 26 Jul 2017 17:57:25 +0200 Subject: [PATCH 108/127] address comments --- tools/internal_ci/helper_scripts/gen_report_index.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/internal_ci/helper_scripts/gen_report_index.sh b/tools/internal_ci/helper_scripts/gen_report_index.sh index cda2fa92a67..0af89c331cd 100755 --- a/tools/internal_ci/helper_scripts/gen_report_index.sh +++ b/tools/internal_ci/helper_scripts/gen_report_index.sh @@ -19,7 +19,7 @@ set -e # change to grpc repo root cd $(dirname $0)/../../.. -# Jenkins URLs are in form "grpc/job/macos/job/experimental/job/jtattermusch_experiment" +# Kororo URLs are in the form "grpc/job/macos/job/master/job/grpc_build_artifacts" KOKORO_JOB_PATH=$(echo "${KOKORO_JOB_NAME}" | sed "s|/|/job/|g") mkdir -p reports From 738a76656cc53edb4715117d63da87c53767fa1a Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Wed, 26 Jul 2017 19:18:00 +0200 Subject: [PATCH 109/127] delete unused grpc_master.cfg --- tools/internal_ci/linux/grpc_master.cfg | 30 ------------------------- 1 file changed, 30 deletions(-) delete mode 100644 tools/internal_ci/linux/grpc_master.cfg diff --git a/tools/internal_ci/linux/grpc_master.cfg b/tools/internal_ci/linux/grpc_master.cfg deleted file mode 100644 index a2784df2974..00000000000 --- a/tools/internal_ci/linux/grpc_master.cfg +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright 2017 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for the internal CI (in protobuf text format) - -# Location of the continuous shell script in repository. -build_file: "grpc/tools/internal_ci/linux/grpc_run_tests_matrix.sh" -timeout_mins: 240 -action { - define_artifacts { - regex: "**/*sponge_log.xml" - regex: "github/grpc/reports/**" - } -} - -env_vars { - key: "RUN_TESTS_FLAGS" - value: "-f basictests linux --inner_jobs 16 -j 1 --internal_ci --bq_result_table aggregate_results" -} From 7b538dda77ec85181d057a5a9c41c84b0e0cf988 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Wed, 26 Jul 2017 19:18:48 +0200 Subject: [PATCH 110/127] grpc_basictests for mac --- tools/internal_ci/macos/grpc_basictests.cfg | 30 ++++++++++++++++++ .../macos/grpc_run_tests_matrix.sh | 31 +++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 tools/internal_ci/macos/grpc_basictests.cfg create mode 100755 tools/internal_ci/macos/grpc_run_tests_matrix.sh diff --git a/tools/internal_ci/macos/grpc_basictests.cfg b/tools/internal_ci/macos/grpc_basictests.cfg new file mode 100644 index 00000000000..ce3609c9ec4 --- /dev/null +++ b/tools/internal_ci/macos/grpc_basictests.cfg @@ -0,0 +1,30 @@ +# Copyright 2017 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for the internal CI (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc/tools/internal_ci/macos/grpc_run_tests_matrix.sh" +timeout_mins: 240 +action { + define_artifacts { + regex: "**/*sponge_log.xml" + regex: "github/grpc/reports/**" + } +} + +env_vars { + key: "RUN_TESTS_FLAGS" + value: "-f basictests macos --internal_ci -j 2 --inner_jobs 4" +} diff --git a/tools/internal_ci/macos/grpc_run_tests_matrix.sh b/tools/internal_ci/macos/grpc_run_tests_matrix.sh new file mode 100755 index 00000000000..9a43e4869b0 --- /dev/null +++ b/tools/internal_ci/macos/grpc_run_tests_matrix.sh @@ -0,0 +1,31 @@ +#!/bin/bash +# Copyright 2017 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -ex + +# change to grpc repo root +cd $(dirname $0)/../../.. + +source tools/internal_ci/helper_scripts/prepare_build_macos_rc + +tools/run_tests/run_tests_matrix.py $RUN_TESTS_FLAGS || FAILED="true" + +# kill port_server.py to prevent the build from hanging +ps aux | grep port_server\\.py | awk '{print $2}' | xargs kill -9 + +if [ "$FAILED" != "" ] +then + exit 1 +fi From bc699ed5da2cf6447cbd9f9cfb97b723dbf04cf9 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Wed, 26 Jul 2017 19:31:30 +0200 Subject: [PATCH 111/127] revamp kokoro windows jobs --- tools/internal_ci/windows/grpc_basictests.cfg | 30 +++++++++++++++++++ tools/internal_ci/windows/grpc_master.cfg | 7 ++++- .../windows/grpc_portability_master.bat | 24 --------------- .../windows/grpc_portability_master.cfg | 7 ++++- ...c_master.bat => grpc_run_tests_matrix.bat} | 2 +- 5 files changed, 43 insertions(+), 27 deletions(-) create mode 100644 tools/internal_ci/windows/grpc_basictests.cfg delete mode 100644 tools/internal_ci/windows/grpc_portability_master.bat rename tools/internal_ci/windows/{grpc_master.bat => grpc_run_tests_matrix.bat} (87%) diff --git a/tools/internal_ci/windows/grpc_basictests.cfg b/tools/internal_ci/windows/grpc_basictests.cfg new file mode 100644 index 00000000000..a116738651f --- /dev/null +++ b/tools/internal_ci/windows/grpc_basictests.cfg @@ -0,0 +1,30 @@ +# Copyright 2017 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for the internal CI (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc/tools/internal_ci/windows/grpc_run_tests_matrix.bat" +timeout_mins: 360 +action { + define_artifacts { + regex: "**/*sponge_log.xml" + regex: "github/grpc/reports/**" + } +} + +env_vars { + key: "RUN_TESTS_FLAGS" + value: "-f basictests windows -j 1 --inner_jobs 8 --internal_ci" +} diff --git a/tools/internal_ci/windows/grpc_master.cfg b/tools/internal_ci/windows/grpc_master.cfg index 786ebc01973..a116738651f 100644 --- a/tools/internal_ci/windows/grpc_master.cfg +++ b/tools/internal_ci/windows/grpc_master.cfg @@ -15,7 +15,7 @@ # Config file for the internal CI (in protobuf text format) # Location of the continuous shell script in repository. -build_file: "grpc/tools/internal_ci/windows/grpc_master.bat" +build_file: "grpc/tools/internal_ci/windows/grpc_run_tests_matrix.bat" timeout_mins: 360 action { define_artifacts { @@ -23,3 +23,8 @@ action { regex: "github/grpc/reports/**" } } + +env_vars { + key: "RUN_TESTS_FLAGS" + value: "-f basictests windows -j 1 --inner_jobs 8 --internal_ci" +} diff --git a/tools/internal_ci/windows/grpc_portability_master.bat b/tools/internal_ci/windows/grpc_portability_master.bat deleted file mode 100644 index c93d56c7e4a..00000000000 --- a/tools/internal_ci/windows/grpc_portability_master.bat +++ /dev/null @@ -1,24 +0,0 @@ -@rem Copyright 2017 gRPC authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem http://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. - -@rem enter repo root -cd /d %~dp0\..\..\.. - -call tools/internal_ci/helper_scripts/prepare_build_windows.bat - -python tools/run_tests/run_tests_matrix.py -f portability windows -j 1 --inner_jobs 8 --internal_ci || goto :error -goto :EOF - -:error -exit /b %errorlevel% diff --git a/tools/internal_ci/windows/grpc_portability_master.cfg b/tools/internal_ci/windows/grpc_portability_master.cfg index 85f69272546..c395cb4a949 100644 --- a/tools/internal_ci/windows/grpc_portability_master.cfg +++ b/tools/internal_ci/windows/grpc_portability_master.cfg @@ -15,7 +15,7 @@ # Config file for the internal CI (in protobuf text format) # Location of the continuous shell script in repository. -build_file: "grpc/tools/internal_ci/windows/grpc_portability_master.bat" +build_file: "grpc/tools/internal_ci/windows/grpc_run_tests_matrix.bat" timeout_mins: 360 action { define_artifacts { @@ -23,3 +23,8 @@ action { regex: "github/grpc/reports/**" } } + +env_vars { + key: "RUN_TESTS_FLAGS" + value: "-f portability windows -j 1 --inner_jobs 8 --internal_ci" +} diff --git a/tools/internal_ci/windows/grpc_master.bat b/tools/internal_ci/windows/grpc_run_tests_matrix.bat similarity index 87% rename from tools/internal_ci/windows/grpc_master.bat rename to tools/internal_ci/windows/grpc_run_tests_matrix.bat index 58eefc301bb..08d834f8b06 100644 --- a/tools/internal_ci/windows/grpc_master.bat +++ b/tools/internal_ci/windows/grpc_run_tests_matrix.bat @@ -17,7 +17,7 @@ cd /d %~dp0\..\..\.. call tools/internal_ci/helper_scripts/prepare_build_windows.bat -python tools/run_tests/run_tests_matrix.py -f basictests windows -j 1 --inner_jobs 8 --internal_ci || goto :error +python tools/run_tests/run_tests_matrix.py %RUN_TESTS_FLAGS% || goto :error goto :EOF :error From 66e7c6785f5a7ccce897c71cbbd685c350c03595 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Wed, 26 Jul 2017 19:34:45 +0200 Subject: [PATCH 112/127] revamp kokoro macos jobs --- tools/internal_ci/macos/grpc_master.cfg | 7 +++++- tools/internal_ci/macos/grpc_master.sh | 31 ------------------------- 2 files changed, 6 insertions(+), 32 deletions(-) delete mode 100755 tools/internal_ci/macos/grpc_master.sh diff --git a/tools/internal_ci/macos/grpc_master.cfg b/tools/internal_ci/macos/grpc_master.cfg index 24c021dfcc2..ce3609c9ec4 100644 --- a/tools/internal_ci/macos/grpc_master.cfg +++ b/tools/internal_ci/macos/grpc_master.cfg @@ -15,7 +15,7 @@ # Config file for the internal CI (in protobuf text format) # Location of the continuous shell script in repository. -build_file: "grpc/tools/internal_ci/macos/grpc_master.sh" +build_file: "grpc/tools/internal_ci/macos/grpc_run_tests_matrix.sh" timeout_mins: 240 action { define_artifacts { @@ -23,3 +23,8 @@ action { regex: "github/grpc/reports/**" } } + +env_vars { + key: "RUN_TESTS_FLAGS" + value: "-f basictests macos --internal_ci -j 2 --inner_jobs 4" +} diff --git a/tools/internal_ci/macos/grpc_master.sh b/tools/internal_ci/macos/grpc_master.sh deleted file mode 100755 index c64666b2dec..00000000000 --- a/tools/internal_ci/macos/grpc_master.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/bash -# Copyright 2017 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set -ex - -# change to grpc repo root -cd $(dirname $0)/../../.. - -source tools/internal_ci/helper_scripts/prepare_build_macos_rc - -tools/run_tests/run_tests_matrix.py -f basictests macos --internal_ci -j 2 --inner_jobs 4 || FAILED="true" - -# kill port_server.py to prevent the build from hanging -ps aux | grep port_server\\.py | awk '{print $2}' | xargs kill -9 - -if [ "$FAILED" != "" ] -then - exit 1 -fi From 36d0056c146fd7fc7f9d37927c265617afabd7e5 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Wed, 26 Jul 2017 19:41:14 +0200 Subject: [PATCH 113/127] prevent timeouts for linux artifact build --- tools/internal_ci/linux/grpc_build_artifacts.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/internal_ci/linux/grpc_build_artifacts.sh b/tools/internal_ci/linux/grpc_build_artifacts.sh index 3997a130878..985243e91b2 100755 --- a/tools/internal_ci/linux/grpc_build_artifacts.sh +++ b/tools/internal_ci/linux/grpc_build_artifacts.sh @@ -26,4 +26,4 @@ set -e # rvm commands are very verbose rvm --default use ruby-2.4.1 set -ex -tools/run_tests/task_runner.py -f artifact linux +tools/run_tests/task_runner.py -f artifact linux -j 6 From 5794061764976c4771f69a3193cd38b3cdba193e Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Wed, 26 Jul 2017 14:29:52 -0700 Subject: [PATCH 114/127] Improvements to grpc_byte_stream API and handling. - Add shutdown() method (to be used in forthcoming call combiner code). - Use a vtable instead of storing method pointers in each instance. - Check all callers of pull() to make sure that they are properly handling errors. - Clarify ownership rules and attempt to adhere to them. - Added a new grpc_caching_byte_stream implementation, which is used in http_client_filter to avoid having to read the whole send_message byte stream before passing control down the stack. (This class may also be used in the retry code I'm working on separately.) - As part of this, did a major rewrite of http_client_filter, which made the code more readable and fixed a number of potential bugs. Note that some of this code is hard to test right now, due to the fact that the send_message byte stream is always a slice_buffer stream, for which next() is always synchronous and no destruction is needed. However, some future work (specifically, my call combiner work and Craig's incremental send work) will start leveraging this. --- CMakeLists.txt | 32 ++ Makefile | 36 ++ build.yaml | 10 + .../filters/http/client/http_client_filter.c | 514 +++++++++--------- .../message_compress_filter.c | 202 ++++--- .../chttp2/transport/chttp2_transport.c | 63 ++- .../ext/transport/inproc/inproc_transport.c | 33 +- src/core/lib/transport/byte_stream.c | 128 ++++- src/core/lib/transport/byte_stream.h | 99 +++- src/core/lib/transport/transport.c | 24 +- src/core/lib/transport/transport.h | 9 + test/core/transport/BUILD | 12 + test/core/transport/byte_stream_test.c | 279 ++++++++++ .../generated/sources_and_headers.json | 17 + tools/run_tests/generated/tests.json | 22 + vsprojects/buildtests_c.sln | 27 + .../byte_stream_test/byte_stream_test.vcxproj | 199 +++++++ .../byte_stream_test.vcxproj.filters | 21 + 18 files changed, 1306 insertions(+), 421 deletions(-) create mode 100644 test/core/transport/byte_stream_test.c create mode 100644 vsprojects/vcxproj/test/byte_stream_test/byte_stream_test.vcxproj create mode 100644 vsprojects/vcxproj/test/byte_stream_test/byte_stream_test.vcxproj.filters diff --git a/CMakeLists.txt b/CMakeLists.txt index 266f2c0774a..f71563a38d7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -394,6 +394,7 @@ add_dependencies(buildtests_c bad_server_response_test) add_dependencies(buildtests_c bdp_estimator_test) add_dependencies(buildtests_c bin_decoder_test) add_dependencies(buildtests_c bin_encoder_test) +add_dependencies(buildtests_c byte_stream_test) add_dependencies(buildtests_c census_context_test) add_dependencies(buildtests_c census_intrusive_hash_map_test) add_dependencies(buildtests_c census_resource_test) @@ -4785,6 +4786,37 @@ target_link_libraries(bin_encoder_test endif (gRPC_BUILD_TESTS) if (gRPC_BUILD_TESTS) +add_executable(byte_stream_test + test/core/transport/byte_stream_test.c +) + + +target_include_directories(byte_stream_test + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include + PRIVATE ${BORINGSSL_ROOT_DIR}/include + PRIVATE ${PROTOBUF_ROOT_DIR}/src + PRIVATE ${BENCHMARK_ROOT_DIR}/include + PRIVATE ${ZLIB_ROOT_DIR} + PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib + PRIVATE ${CARES_BUILD_INCLUDE_DIR} + PRIVATE ${CARES_INCLUDE_DIR} + PRIVATE ${CARES_PLATFORM_INCLUDE_DIR} + PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares + PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include +) + +target_link_libraries(byte_stream_test + ${_gRPC_ALLTARGETS_LIBRARIES} + grpc_test_util + grpc + gpr_test_util + gpr +) + +endif (gRPC_BUILD_TESTS) +if (gRPC_BUILD_TESTS) + add_executable(census_context_test test/core/census/context_test.c ) diff --git a/Makefile b/Makefile index 7b53024b6c1..98cfb04e54a 100644 --- a/Makefile +++ b/Makefile @@ -954,6 +954,7 @@ bad_server_response_test: $(BINDIR)/$(CONFIG)/bad_server_response_test bdp_estimator_test: $(BINDIR)/$(CONFIG)/bdp_estimator_test bin_decoder_test: $(BINDIR)/$(CONFIG)/bin_decoder_test bin_encoder_test: $(BINDIR)/$(CONFIG)/bin_encoder_test +byte_stream_test: $(BINDIR)/$(CONFIG)/byte_stream_test census_context_test: $(BINDIR)/$(CONFIG)/census_context_test census_intrusive_hash_map_test: $(BINDIR)/$(CONFIG)/census_intrusive_hash_map_test census_resource_test: $(BINDIR)/$(CONFIG)/census_resource_test @@ -1345,6 +1346,7 @@ buildtests_c: privatelibs_c \ $(BINDIR)/$(CONFIG)/bdp_estimator_test \ $(BINDIR)/$(CONFIG)/bin_decoder_test \ $(BINDIR)/$(CONFIG)/bin_encoder_test \ + $(BINDIR)/$(CONFIG)/byte_stream_test \ $(BINDIR)/$(CONFIG)/census_context_test \ $(BINDIR)/$(CONFIG)/census_intrusive_hash_map_test \ $(BINDIR)/$(CONFIG)/census_resource_test \ @@ -1746,6 +1748,8 @@ test_c: buildtests_c $(Q) $(BINDIR)/$(CONFIG)/bin_decoder_test || ( echo test bin_decoder_test failed ; exit 1 ) $(E) "[RUN] Testing bin_encoder_test" $(Q) $(BINDIR)/$(CONFIG)/bin_encoder_test || ( echo test bin_encoder_test failed ; exit 1 ) + $(E) "[RUN] Testing byte_stream_test" + $(Q) $(BINDIR)/$(CONFIG)/byte_stream_test || ( echo test byte_stream_test failed ; exit 1 ) $(E) "[RUN] Testing census_context_test" $(Q) $(BINDIR)/$(CONFIG)/census_context_test || ( echo test census_context_test failed ; exit 1 ) $(E) "[RUN] Testing census_intrusive_hash_map_test" @@ -8411,6 +8415,38 @@ endif endif +BYTE_STREAM_TEST_SRC = \ + test/core/transport/byte_stream_test.c \ + +BYTE_STREAM_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(BYTE_STREAM_TEST_SRC)))) +ifeq ($(NO_SECURE),true) + +# You can't build secure targets if you don't have OpenSSL. + +$(BINDIR)/$(CONFIG)/byte_stream_test: openssl_dep_error + +else + + + +$(BINDIR)/$(CONFIG)/byte_stream_test: $(BYTE_STREAM_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a + $(E) "[LD] Linking $@" + $(Q) mkdir -p `dirname $@` + $(Q) $(LD) $(LDFLAGS) $(BYTE_STREAM_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/byte_stream_test + +endif + +$(OBJDIR)/$(CONFIG)/test/core/transport/byte_stream_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a + +deps_byte_stream_test: $(BYTE_STREAM_TEST_OBJS:.o=.dep) + +ifneq ($(NO_SECURE),true) +ifneq ($(NO_DEPS),true) +-include $(BYTE_STREAM_TEST_OBJS:.o=.dep) +endif +endif + + CENSUS_CONTEXT_TEST_SRC = \ test/core/census/context_test.c \ diff --git a/build.yaml b/build.yaml index 198467bf5ad..9c2504af71f 100644 --- a/build.yaml +++ b/build.yaml @@ -1702,6 +1702,16 @@ targets: deps: - grpc_test_util - grpc +- name: byte_stream_test + build: test + language: c + src: + - test/core/transport/byte_stream_test.c + deps: + - grpc_test_util + - grpc + - gpr_test_util + - gpr - name: census_context_test build: test language: c diff --git a/src/core/ext/filters/http/client/http_client_filter.c b/src/core/ext/filters/http/client/http_client_filter.c index 90f0aed7a0d..3ca01a41b53 100644 --- a/src/core/ext/filters/http/client/http_client_filter.c +++ b/src/core/ext/filters/http/client/http_client_filter.c @@ -36,41 +36,29 @@ static const size_t kMaxPayloadSizeForGet = 2048; typedef struct call_data { + // State for handling send_initial_metadata ops. grpc_linked_mdelem method; grpc_linked_mdelem scheme; grpc_linked_mdelem authority; grpc_linked_mdelem te_trailers; grpc_linked_mdelem content_type; grpc_linked_mdelem user_agent; - + // State for handling recv_initial_metadata ops. grpc_metadata_batch *recv_initial_metadata; + grpc_closure *original_recv_initial_metadata_ready; + grpc_closure recv_initial_metadata_ready; + // State for handling recv_trailing_metadata ops. grpc_metadata_batch *recv_trailing_metadata; - uint8_t *payload_bytes; - - /* Vars to read data off of send_message */ - grpc_transport_stream_op_batch *send_op; - uint32_t send_length; - uint32_t send_flags; - grpc_slice incoming_slice; - grpc_slice_buffer_stream replacement_stream; - grpc_slice_buffer slices; - /* flag that indicates that all slices of send_messages aren't availble */ - bool send_message_blocked; - - /** Closure to call when finished with the hc_on_recv hook */ - grpc_closure *on_done_recv_initial_metadata; - grpc_closure *on_done_recv_trailing_metadata; - grpc_closure *on_complete; - grpc_closure *post_send; - - /** Receive closures are chained: we inject this closure as the on_done_recv - up-call on transport_op, and remember to call our on_done_recv member - after handling it. */ - grpc_closure hc_on_recv_initial_metadata; - grpc_closure hc_on_recv_trailing_metadata; - grpc_closure hc_on_complete; - grpc_closure got_slice; - grpc_closure send_done; + grpc_closure *original_recv_trailing_metadata_on_complete; + grpc_closure recv_trailing_metadata_on_complete; + // State for handling send_message ops. + grpc_transport_stream_op_batch *send_message_batch; + size_t send_message_bytes_read; + grpc_byte_stream_cache send_message_cache; + grpc_caching_byte_stream send_message_caching_stream; + grpc_closure on_send_message_next_done; + grpc_closure *original_send_message_on_complete; + grpc_closure send_message_on_complete; } call_data; typedef struct channel_data { @@ -148,7 +136,7 @@ static grpc_error *client_filter_incoming_metadata(grpc_exec_ctx *exec_ctx, return GRPC_ERROR_NONE; } -static void hc_on_recv_initial_metadata(grpc_exec_ctx *exec_ctx, +static void recv_initial_metadata_ready(grpc_exec_ctx *exec_ctx, void *user_data, grpc_error *error) { grpc_call_element *elem = user_data; call_data *calld = elem->call_data; @@ -158,11 +146,13 @@ static void hc_on_recv_initial_metadata(grpc_exec_ctx *exec_ctx, } else { GRPC_ERROR_REF(error); } - GRPC_CLOSURE_RUN(exec_ctx, calld->on_done_recv_initial_metadata, error); + GRPC_CLOSURE_RUN(exec_ctx, calld->original_recv_initial_metadata_ready, + error); } -static void hc_on_recv_trailing_metadata(grpc_exec_ctx *exec_ctx, - void *user_data, grpc_error *error) { +static void recv_trailing_metadata_on_complete(grpc_exec_ctx *exec_ctx, + void *user_data, + grpc_error *error) { grpc_call_element *elem = user_data; call_data *calld = elem->call_data; if (error == GRPC_ERROR_NONE) { @@ -171,25 +161,131 @@ static void hc_on_recv_trailing_metadata(grpc_exec_ctx *exec_ctx, } else { GRPC_ERROR_REF(error); } - GRPC_CLOSURE_RUN(exec_ctx, calld->on_done_recv_trailing_metadata, error); + GRPC_CLOSURE_RUN(exec_ctx, calld->original_recv_trailing_metadata_on_complete, + error); } -static void hc_on_complete(grpc_exec_ctx *exec_ctx, void *user_data, - grpc_error *error) { - grpc_call_element *elem = user_data; - call_data *calld = elem->call_data; - if (calld->payload_bytes) { - gpr_free(calld->payload_bytes); - calld->payload_bytes = NULL; +static void send_message_on_complete(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + grpc_call_element *elem = (grpc_call_element *)arg; + call_data *calld = (call_data *)elem->call_data; + grpc_byte_stream_cache_destroy(exec_ctx, &calld->send_message_cache); + GRPC_CLOSURE_RUN(exec_ctx, calld->original_send_message_on_complete, + GRPC_ERROR_REF(error)); +} + +// Pulls a slice from the send_message byte stream, updating +// calld->send_message_bytes_read. +static grpc_error *pull_slice_from_send_message(grpc_exec_ctx *exec_ctx, + call_data *calld) { + grpc_slice incoming_slice; + grpc_error *error = grpc_byte_stream_pull( + exec_ctx, &calld->send_message_caching_stream.base, &incoming_slice); + if (error == GRPC_ERROR_NONE) { + calld->send_message_bytes_read += GRPC_SLICE_LENGTH(incoming_slice); + grpc_slice_unref_internal(exec_ctx, incoming_slice); } - calld->on_complete->cb(exec_ctx, calld->on_complete->cb_arg, error); + return error; } -static void send_done(grpc_exec_ctx *exec_ctx, void *elemp, grpc_error *error) { - grpc_call_element *elem = elemp; - call_data *calld = elem->call_data; - grpc_slice_buffer_reset_and_unref_internal(exec_ctx, &calld->slices); - calld->post_send->cb(exec_ctx, calld->post_send->cb_arg, error); +// Reads as many slices as possible from the send_message byte stream. +// Upon successful return, if calld->send_message_bytes_read == +// calld->send_message_caching_stream.base.length, then we have completed +// reading from the byte stream; otherwise, an async read has been dispatched +// and on_send_message_next_done() will be invoked when it is complete. +static grpc_error *read_all_available_send_message_data(grpc_exec_ctx *exec_ctx, + call_data *calld) { + while (grpc_byte_stream_next(exec_ctx, + &calld->send_message_caching_stream.base, + ~(size_t)0, &calld->on_send_message_next_done)) { + grpc_error *error = pull_slice_from_send_message(exec_ctx, calld); + if (error != GRPC_ERROR_NONE) return error; + if (calld->send_message_bytes_read == + calld->send_message_caching_stream.base.length) { + break; + } + } + return GRPC_ERROR_NONE; +} + +// Async callback for grpc_byte_stream_next(). +static void on_send_message_next_done(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + grpc_call_element *elem = (grpc_call_element *)arg; + call_data *calld = (call_data *)elem->call_data; + if (error != GRPC_ERROR_NONE) { + grpc_transport_stream_op_batch_finish_with_failure( + exec_ctx, calld->send_message_batch, error); + return; + } + error = pull_slice_from_send_message(exec_ctx, calld); + if (error != GRPC_ERROR_NONE) { + grpc_transport_stream_op_batch_finish_with_failure( + exec_ctx, calld->send_message_batch, error); + return; + } + // There may or may not be more to read, but we don't care. If we got + // here, then we know that all of the data was not available + // synchronously, so we were not able to do a cached call. Instead, + // we just reset the byte stream and then send down the batch as-is. + grpc_caching_byte_stream_reset(&calld->send_message_caching_stream); + grpc_call_next_op(exec_ctx, elem, calld->send_message_batch); +} + +static char *slice_buffer_to_string(grpc_slice_buffer *slice_buffer) { + char *payload_bytes = gpr_malloc(slice_buffer->length + 1); + size_t offset = 0; + for (size_t i = 0; i < slice_buffer->count; ++i) { + memcpy(payload_bytes + offset, + GRPC_SLICE_START_PTR(slice_buffer->slices[i]), + GRPC_SLICE_LENGTH(slice_buffer->slices[i])); + offset += GRPC_SLICE_LENGTH(slice_buffer->slices[i]); + } + *(payload_bytes + offset) = '\0'; + return payload_bytes; +} + +// Modifies the path entry in the batch's send_initial_metadata to +// append the base64-encoded query for a GET request. +static grpc_error *update_path_for_get(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem, + grpc_transport_stream_op_batch *batch) { + call_data *calld = (call_data *)elem->call_data; + grpc_slice path_slice = + GRPC_MDVALUE(batch->payload->send_initial_metadata.send_initial_metadata + ->idx.named.path->md); + /* sum up individual component's lengths and allocate enough memory to + * hold combined path+query */ + size_t estimated_len = GRPC_SLICE_LENGTH(path_slice); + estimated_len++; /* for the '?' */ + estimated_len += grpc_base64_estimate_encoded_size( + batch->payload->send_message.send_message->length, true /* url_safe */, + false /* multi_line */); + grpc_slice path_with_query_slice = GRPC_SLICE_MALLOC(estimated_len); + /* memcopy individual pieces into this slice */ + char *write_ptr = (char *)GRPC_SLICE_START_PTR(path_with_query_slice); + char *original_path = (char *)GRPC_SLICE_START_PTR(path_slice); + memcpy(write_ptr, original_path, GRPC_SLICE_LENGTH(path_slice)); + write_ptr += GRPC_SLICE_LENGTH(path_slice); + *write_ptr++ = '?'; + char *payload_bytes = + slice_buffer_to_string(&calld->send_message_cache.cache_buffer); + grpc_base64_encode_core((char *)write_ptr, payload_bytes, + batch->payload->send_message.send_message->length, + true /* url_safe */, false /* multi_line */); + gpr_free(payload_bytes); + /* remove trailing unused memory and add trailing 0 to terminate string */ + char *t = (char *)GRPC_SLICE_START_PTR(path_with_query_slice); + /* safe to use strlen since base64_encode will always add '\0' */ + path_with_query_slice = + grpc_slice_sub_no_ref(path_with_query_slice, 0, strlen(t)); + /* substitute previous path with the new path+query */ + grpc_mdelem mdelem_path_and_query = + grpc_mdelem_from_slices(exec_ctx, GRPC_MDSTR_PATH, path_with_query_slice); + grpc_metadata_batch *b = + batch->payload->send_initial_metadata.send_initial_metadata; + return grpc_metadata_batch_substitute(exec_ctx, b, b->idx.named.path, + mdelem_path_and_query); } static void remove_if_present(grpc_exec_ctx *exec_ctx, @@ -200,273 +296,153 @@ static void remove_if_present(grpc_exec_ctx *exec_ctx, } } -static void continue_send_message(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem) { +static void hc_start_transport_stream_op_batch( + grpc_exec_ctx *exec_ctx, grpc_call_element *elem, + grpc_transport_stream_op_batch *batch) { call_data *calld = elem->call_data; - uint8_t *wrptr = calld->payload_bytes; - while (grpc_byte_stream_next( - exec_ctx, calld->send_op->payload->send_message.send_message, ~(size_t)0, - &calld->got_slice)) { - grpc_byte_stream_pull(exec_ctx, - calld->send_op->payload->send_message.send_message, - &calld->incoming_slice); - if (GRPC_SLICE_LENGTH(calld->incoming_slice) > 0) { - memcpy(wrptr, GRPC_SLICE_START_PTR(calld->incoming_slice), - GRPC_SLICE_LENGTH(calld->incoming_slice)); - } - wrptr += GRPC_SLICE_LENGTH(calld->incoming_slice); - grpc_slice_buffer_add(&calld->slices, calld->incoming_slice); - if (calld->send_length == calld->slices.length) { - calld->send_message_blocked = false; - break; - } - } -} + channel_data *channeld = elem->channel_data; + GPR_TIMER_BEGIN("hc_start_transport_stream_op_batch", 0); + GRPC_CALL_LOG_OP(GPR_INFO, elem, batch); -static void got_slice(grpc_exec_ctx *exec_ctx, void *elemp, grpc_error *error) { - grpc_call_element *elem = elemp; - call_data *calld = elem->call_data; - calld->send_message_blocked = false; - if (GRPC_ERROR_NONE != - grpc_byte_stream_pull(exec_ctx, - calld->send_op->payload->send_message.send_message, - &calld->incoming_slice)) { - /* Should never reach here */ - abort(); - } - grpc_slice_buffer_add(&calld->slices, calld->incoming_slice); - if (calld->send_length == calld->slices.length) { - /* Pass down the original send_message op that was blocked.*/ - grpc_slice_buffer_stream_init(&calld->replacement_stream, &calld->slices, - calld->send_flags); - calld->send_op->payload->send_message.send_message = - &calld->replacement_stream.base; - calld->post_send = calld->send_op->on_complete; - calld->send_op->on_complete = &calld->send_done; - grpc_call_next_op(exec_ctx, elem, calld->send_op); - } else { - continue_send_message(exec_ctx, elem); + if (batch->recv_initial_metadata) { + /* substitute our callback for the higher callback */ + calld->recv_initial_metadata = + batch->payload->recv_initial_metadata.recv_initial_metadata; + calld->original_recv_initial_metadata_ready = + batch->payload->recv_initial_metadata.recv_initial_metadata_ready; + batch->payload->recv_initial_metadata.recv_initial_metadata_ready = + &calld->recv_initial_metadata_ready; } -} -static grpc_error *hc_mutate_op(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem, - grpc_transport_stream_op_batch *op) { - /* grab pointers to our data from the call element */ - call_data *calld = elem->call_data; - channel_data *channeld = elem->channel_data; - grpc_error *error; + if (batch->recv_trailing_metadata) { + /* substitute our callback for the higher callback */ + calld->recv_trailing_metadata = + batch->payload->recv_trailing_metadata.recv_trailing_metadata; + calld->original_recv_trailing_metadata_on_complete = batch->on_complete; + batch->on_complete = &calld->recv_trailing_metadata_on_complete; + } - if (op->send_initial_metadata) { - /* Decide which HTTP VERB to use. We use GET if the request is marked - cacheable, and the operation contains both initial metadata and send - message, and the payload is below the size threshold, and all the data - for this request is immediately available. */ + grpc_error *error = GRPC_ERROR_NONE; + bool batch_will_be_handled_asynchronously = false; + if (batch->send_initial_metadata) { + // Decide which HTTP VERB to use. We use GET if the request is marked + // cacheable, and the operation contains both initial metadata and send + // message, and the payload is below the size threshold, and all the data + // for this request is immediately available. grpc_mdelem method = GRPC_MDELEM_METHOD_POST; - if (op->send_message && - (op->payload->send_initial_metadata.send_initial_metadata_flags & + if (batch->send_message && + (batch->payload->send_initial_metadata.send_initial_metadata_flags & GRPC_INITIAL_METADATA_CACHEABLE_REQUEST) && - op->payload->send_message.send_message->length < + batch->payload->send_message.send_message->length < channeld->max_payload_size_for_get) { - method = GRPC_MDELEM_METHOD_GET; - /* The following write to calld->send_message_blocked isn't racy with - reads in hc_start_transport_op (which deals with SEND_MESSAGE ops) because - being here means ops->send_message is not NULL, which is primarily - guarding the read there. */ - calld->send_message_blocked = true; - } else if (op->payload->send_initial_metadata.send_initial_metadata_flags & - GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST) { - method = GRPC_MDELEM_METHOD_PUT; - } - - /* Attempt to read the data from send_message and create a header field. */ - if (grpc_mdelem_eq(method, GRPC_MDELEM_METHOD_GET)) { - /* allocate memory to hold the entire payload */ - calld->payload_bytes = - gpr_malloc(op->payload->send_message.send_message->length); - - /* read slices of send_message and copy into payload_bytes */ - calld->send_op = op; - calld->send_length = op->payload->send_message.send_message->length; - calld->send_flags = op->payload->send_message.send_message->flags; - continue_send_message(exec_ctx, elem); - - if (calld->send_message_blocked == false) { - /* when all the send_message data is available, then modify the path - * MDELEM by appending base64 encoded query to the path */ - const int k_url_safe = 1; - const int k_multi_line = 0; - const unsigned char k_query_separator = '?'; - - grpc_slice path_slice = - GRPC_MDVALUE(op->payload->send_initial_metadata - .send_initial_metadata->idx.named.path->md); - /* sum up individual component's lengths and allocate enough memory to - * hold combined path+query */ - size_t estimated_len = GRPC_SLICE_LENGTH(path_slice); - estimated_len++; /* for the '?' */ - estimated_len += grpc_base64_estimate_encoded_size( - op->payload->send_message.send_message->length, k_url_safe, - k_multi_line); - grpc_slice path_with_query_slice = GRPC_SLICE_MALLOC(estimated_len); - - /* memcopy individual pieces into this slice */ - uint8_t *write_ptr = - (uint8_t *)GRPC_SLICE_START_PTR(path_with_query_slice); - uint8_t *original_path = (uint8_t *)GRPC_SLICE_START_PTR(path_slice); - memcpy(write_ptr, original_path, GRPC_SLICE_LENGTH(path_slice)); - write_ptr += GRPC_SLICE_LENGTH(path_slice); - - *write_ptr = k_query_separator; - write_ptr++; /* for the '?' */ - - grpc_base64_encode_core((char *)write_ptr, calld->payload_bytes, - op->payload->send_message.send_message->length, - k_url_safe, k_multi_line); - - /* remove trailing unused memory and add trailing 0 to terminate string - */ - char *t = (char *)GRPC_SLICE_START_PTR(path_with_query_slice); - /* safe to use strlen since base64_encode will always add '\0' */ - path_with_query_slice = - grpc_slice_sub_no_ref(path_with_query_slice, 0, strlen(t)); - - /* substitute previous path with the new path+query */ - grpc_mdelem mdelem_path_and_query = grpc_mdelem_from_slices( - exec_ctx, GRPC_MDSTR_PATH, path_with_query_slice); - grpc_metadata_batch *b = - op->payload->send_initial_metadata.send_initial_metadata; - error = grpc_metadata_batch_substitute(exec_ctx, b, b->idx.named.path, - mdelem_path_and_query); - if (error != GRPC_ERROR_NONE) return error; - - calld->on_complete = op->on_complete; - op->on_complete = &calld->hc_on_complete; - op->send_message = false; + calld->send_message_bytes_read = 0; + grpc_byte_stream_cache_init(&calld->send_message_cache, + batch->payload->send_message.send_message); + grpc_caching_byte_stream_init(&calld->send_message_caching_stream, + &calld->send_message_cache); + batch->payload->send_message.send_message = + &calld->send_message_caching_stream.base; + calld->original_send_message_on_complete = batch->on_complete; + batch->on_complete = &calld->send_message_on_complete; + calld->send_message_batch = batch; + error = read_all_available_send_message_data(exec_ctx, calld); + if (error != GRPC_ERROR_NONE) goto done; + // If all the data has been read, then we can use GET. + if (calld->send_message_bytes_read == + calld->send_message_caching_stream.base.length) { + method = GRPC_MDELEM_METHOD_GET; + error = update_path_for_get(exec_ctx, elem, batch); + if (error != GRPC_ERROR_NONE) goto done; + batch->send_message = false; + grpc_byte_stream_destroy(exec_ctx, + &calld->send_message_caching_stream.base); } else { - /* Not all data is available. Fall back to POST. */ + // Not all data is available. The batch will be sent down + // asynchronously in on_send_message_next_done(). + batch_will_be_handled_asynchronously = true; + // Fall back to POST. gpr_log(GPR_DEBUG, - "Request is marked Cacheable but not all data is available.\ - Falling back to POST"); - method = GRPC_MDELEM_METHOD_POST; + "Request is marked Cacheable but not all data is available. " + "Falling back to POST"); } + } else if (batch->payload->send_initial_metadata + .send_initial_metadata_flags & + GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST) { + method = GRPC_MDELEM_METHOD_PUT; } - remove_if_present(exec_ctx, - op->payload->send_initial_metadata.send_initial_metadata, - GRPC_BATCH_METHOD); - remove_if_present(exec_ctx, - op->payload->send_initial_metadata.send_initial_metadata, - GRPC_BATCH_SCHEME); - remove_if_present(exec_ctx, - op->payload->send_initial_metadata.send_initial_metadata, - GRPC_BATCH_TE); - remove_if_present(exec_ctx, - op->payload->send_initial_metadata.send_initial_metadata, - GRPC_BATCH_CONTENT_TYPE); - remove_if_present(exec_ctx, - op->payload->send_initial_metadata.send_initial_metadata, - GRPC_BATCH_USER_AGENT); + remove_if_present( + exec_ctx, batch->payload->send_initial_metadata.send_initial_metadata, + GRPC_BATCH_METHOD); + remove_if_present( + exec_ctx, batch->payload->send_initial_metadata.send_initial_metadata, + GRPC_BATCH_SCHEME); + remove_if_present( + exec_ctx, batch->payload->send_initial_metadata.send_initial_metadata, + GRPC_BATCH_TE); + remove_if_present( + exec_ctx, batch->payload->send_initial_metadata.send_initial_metadata, + GRPC_BATCH_CONTENT_TYPE); + remove_if_present( + exec_ctx, batch->payload->send_initial_metadata.send_initial_metadata, + GRPC_BATCH_USER_AGENT); /* Send : prefixed headers, which have to be before any application layer headers. */ error = grpc_metadata_batch_add_head( - exec_ctx, op->payload->send_initial_metadata.send_initial_metadata, + exec_ctx, batch->payload->send_initial_metadata.send_initial_metadata, &calld->method, method); - if (error != GRPC_ERROR_NONE) return error; + if (error != GRPC_ERROR_NONE) goto done; error = grpc_metadata_batch_add_head( - exec_ctx, op->payload->send_initial_metadata.send_initial_metadata, + exec_ctx, batch->payload->send_initial_metadata.send_initial_metadata, &calld->scheme, channeld->static_scheme); - if (error != GRPC_ERROR_NONE) return error; + if (error != GRPC_ERROR_NONE) goto done; error = grpc_metadata_batch_add_tail( - exec_ctx, op->payload->send_initial_metadata.send_initial_metadata, + exec_ctx, batch->payload->send_initial_metadata.send_initial_metadata, &calld->te_trailers, GRPC_MDELEM_TE_TRAILERS); - if (error != GRPC_ERROR_NONE) return error; + if (error != GRPC_ERROR_NONE) goto done; error = grpc_metadata_batch_add_tail( - exec_ctx, op->payload->send_initial_metadata.send_initial_metadata, + exec_ctx, batch->payload->send_initial_metadata.send_initial_metadata, &calld->content_type, GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC); - if (error != GRPC_ERROR_NONE) return error; + if (error != GRPC_ERROR_NONE) goto done; error = grpc_metadata_batch_add_tail( - exec_ctx, op->payload->send_initial_metadata.send_initial_metadata, + exec_ctx, batch->payload->send_initial_metadata.send_initial_metadata, &calld->user_agent, GRPC_MDELEM_REF(channeld->user_agent)); - if (error != GRPC_ERROR_NONE) return error; + if (error != GRPC_ERROR_NONE) goto done; } - if (op->recv_initial_metadata) { - /* substitute our callback for the higher callback */ - calld->recv_initial_metadata = - op->payload->recv_initial_metadata.recv_initial_metadata; - calld->on_done_recv_initial_metadata = - op->payload->recv_initial_metadata.recv_initial_metadata_ready; - op->payload->recv_initial_metadata.recv_initial_metadata_ready = - &calld->hc_on_recv_initial_metadata; - } - - if (op->recv_trailing_metadata) { - /* substitute our callback for the higher callback */ - calld->recv_trailing_metadata = - op->payload->recv_trailing_metadata.recv_trailing_metadata; - calld->on_done_recv_trailing_metadata = op->on_complete; - op->on_complete = &calld->hc_on_recv_trailing_metadata; - } - - return GRPC_ERROR_NONE; -} - -static void hc_start_transport_op(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem, - grpc_transport_stream_op_batch *op) { - GPR_TIMER_BEGIN("hc_start_transport_op", 0); - GRPC_CALL_LOG_OP(GPR_INFO, elem, op); - grpc_error *error = hc_mutate_op(exec_ctx, elem, op); +done: if (error != GRPC_ERROR_NONE) { - grpc_transport_stream_op_batch_finish_with_failure(exec_ctx, op, error); - } else { - call_data *calld = elem->call_data; - if (op->send_message && calld->send_message_blocked) { - /* Don't forward the op. send_message contains slices that aren't ready - yet. The call will be forwarded by the op_complete of slice read call. - */ - } else { - grpc_call_next_op(exec_ctx, elem, op); - } + grpc_transport_stream_op_batch_finish_with_failure( + exec_ctx, calld->send_message_batch, error); + } else if (!batch_will_be_handled_asynchronously) { + grpc_call_next_op(exec_ctx, elem, batch); } - GPR_TIMER_END("hc_start_transport_op", 0); + GPR_TIMER_END("hc_start_transport_stream_op_batch", 0); } /* Constructor for call_data */ static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, const grpc_call_element_args *args) { - call_data *calld = elem->call_data; - calld->on_done_recv_initial_metadata = NULL; - calld->on_done_recv_trailing_metadata = NULL; - calld->on_complete = NULL; - calld->payload_bytes = NULL; - calld->send_message_blocked = false; - grpc_slice_buffer_init(&calld->slices); - GRPC_CLOSURE_INIT(&calld->hc_on_recv_initial_metadata, - hc_on_recv_initial_metadata, elem, - grpc_schedule_on_exec_ctx); - GRPC_CLOSURE_INIT(&calld->hc_on_recv_trailing_metadata, - hc_on_recv_trailing_metadata, elem, + call_data *calld = (call_data *)elem->call_data; + GRPC_CLOSURE_INIT(&calld->recv_initial_metadata_ready, + recv_initial_metadata_ready, elem, grpc_schedule_on_exec_ctx); - GRPC_CLOSURE_INIT(&calld->hc_on_complete, hc_on_complete, elem, - grpc_schedule_on_exec_ctx); - GRPC_CLOSURE_INIT(&calld->got_slice, got_slice, elem, - grpc_schedule_on_exec_ctx); - GRPC_CLOSURE_INIT(&calld->send_done, send_done, elem, + GRPC_CLOSURE_INIT(&calld->recv_trailing_metadata_on_complete, + recv_trailing_metadata_on_complete, elem, grpc_schedule_on_exec_ctx); + GRPC_CLOSURE_INIT(&calld->send_message_on_complete, send_message_on_complete, + elem, grpc_schedule_on_exec_ctx); + GRPC_CLOSURE_INIT(&calld->on_send_message_next_done, + on_send_message_next_done, elem, grpc_schedule_on_exec_ctx); return GRPC_ERROR_NONE; } /* Destructor for call_data */ static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, const grpc_call_final_info *final_info, - grpc_closure *ignored) { - call_data *calld = elem->call_data; - grpc_slice_buffer_destroy_internal(exec_ctx, &calld->slices); -} + grpc_closure *ignored) {} static grpc_mdelem scheme_from_args(const grpc_channel_args *args) { unsigned i; @@ -580,7 +556,7 @@ static void destroy_channel_elem(grpc_exec_ctx *exec_ctx, } const grpc_channel_filter grpc_http_client_filter = { - hc_start_transport_op, + hc_start_transport_stream_op_batch, grpc_channel_next_op, sizeof(call_data), init_call_elem, diff --git a/src/core/ext/filters/http/message_compress/message_compress_filter.c b/src/core/ext/filters/http/message_compress/message_compress_filter.c index 71a8bc5bec2..20a3488115e 100644 --- a/src/core/ext/filters/http/message_compress/message_compress_filter.c +++ b/src/core/ext/filters/http/message_compress/message_compress_filter.c @@ -61,14 +61,11 @@ typedef struct call_data { pointer | CANCELLED_BIT - request was cancelled with error pointed to */ gpr_atm send_initial_metadata_state; - grpc_transport_stream_op_batch *send_op; - uint32_t send_length; - uint32_t send_flags; - grpc_slice incoming_slice; + grpc_transport_stream_op_batch *send_message_batch; grpc_slice_buffer_stream replacement_stream; - grpc_closure *post_send; - grpc_closure send_done; - grpc_closure got_slice; + grpc_closure *original_send_message_on_complete; + grpc_closure send_message_on_complete; + grpc_closure on_send_message_next_done; } call_data; typedef struct channel_data { @@ -164,24 +161,25 @@ static grpc_error *process_send_initial_metadata( return error; } -static void continue_send_message(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem); - -static void send_done(grpc_exec_ctx *exec_ctx, void *elemp, grpc_error *error) { - grpc_call_element *elem = elemp; - call_data *calld = elem->call_data; +static void send_message_on_complete(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + grpc_call_element *elem = (grpc_call_element *)arg; + call_data *calld = (call_data *)elem->call_data; grpc_slice_buffer_reset_and_unref_internal(exec_ctx, &calld->slices); - calld->post_send->cb(exec_ctx, calld->post_send->cb_arg, error); + GRPC_CLOSURE_RUN(exec_ctx, calld->original_send_message_on_complete, + GRPC_ERROR_REF(error)); } static void finish_send_message(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) { - call_data *calld = elem->call_data; - int did_compress; + call_data *calld = (call_data *)elem->call_data; + // Compress the data if appropriate. grpc_slice_buffer tmp; grpc_slice_buffer_init(&tmp); - did_compress = grpc_msg_compress(exec_ctx, calld->compression_algorithm, - &calld->slices, &tmp); + uint32_t send_flags = + calld->send_message_batch->payload->send_message.send_message->flags; + const bool did_compress = grpc_msg_compress( + exec_ctx, calld->compression_algorithm, &calld->slices, &tmp); if (did_compress) { if (GRPC_TRACER_ON(grpc_compression_trace)) { char *algo_name; @@ -195,7 +193,7 @@ static void finish_send_message(grpc_exec_ctx *exec_ctx, algo_name, before_size, after_size, 100 * savings_ratio); } grpc_slice_buffer_swap(&calld->slices, &tmp); - calld->send_flags |= GRPC_WRITE_INTERNAL_COMPRESS; + send_flags |= GRPC_WRITE_INTERNAL_COMPRESS; } else { if (GRPC_TRACER_ON(grpc_compression_trace)) { char *algo_name; @@ -207,83 +205,118 @@ static void finish_send_message(grpc_exec_ctx *exec_ctx, algo_name, calld->slices.length); } } - grpc_slice_buffer_destroy_internal(exec_ctx, &tmp); - + // Swap out the original byte stream with our new one and send the + // batch down. + grpc_byte_stream_destroy( + exec_ctx, calld->send_message_batch->payload->send_message.send_message); grpc_slice_buffer_stream_init(&calld->replacement_stream, &calld->slices, - calld->send_flags); - calld->send_op->payload->send_message.send_message = + send_flags); + calld->send_message_batch->payload->send_message.send_message = &calld->replacement_stream.base; - calld->post_send = calld->send_op->on_complete; - calld->send_op->on_complete = &calld->send_done; - - grpc_call_next_op(exec_ctx, elem, calld->send_op); + calld->original_send_message_on_complete = + calld->send_message_batch->on_complete; + calld->send_message_batch->on_complete = &calld->send_message_on_complete; + grpc_call_next_op(exec_ctx, elem, calld->send_message_batch); } -static void got_slice(grpc_exec_ctx *exec_ctx, void *elemp, grpc_error *error) { - grpc_call_element *elem = elemp; - call_data *calld = elem->call_data; - if (GRPC_ERROR_NONE != - grpc_byte_stream_pull(exec_ctx, - calld->send_op->payload->send_message.send_message, - &calld->incoming_slice)) { - /* Should never reach here */ - abort(); - } - grpc_slice_buffer_add(&calld->slices, calld->incoming_slice); - if (calld->send_length == calld->slices.length) { - finish_send_message(exec_ctx, elem); - } else { - continue_send_message(exec_ctx, elem); +// Pulls a slice from the send_message byte stream and adds it to calld->slices. +static grpc_error *pull_slice_from_send_message(grpc_exec_ctx *exec_ctx, + call_data *calld) { + grpc_slice incoming_slice; + grpc_error *error = grpc_byte_stream_pull( + exec_ctx, calld->send_message_batch->payload->send_message.send_message, + &incoming_slice); + if (error == GRPC_ERROR_NONE) { + grpc_slice_buffer_add(&calld->slices, incoming_slice); } + return error; } -static void continue_send_message(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem) { - call_data *calld = elem->call_data; +// Reads as many slices as possible from the send_message byte stream. +// If all data has been read, invokes finish_send_message(). Otherwise, +// an async call to grpc_byte_stream_next() has been started, which will +// eventually result in calling on_send_message_next_done(). +static grpc_error *continue_reading_send_message(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem) { + call_data *calld = (call_data *)elem->call_data; while (grpc_byte_stream_next( - exec_ctx, calld->send_op->payload->send_message.send_message, ~(size_t)0, - &calld->got_slice)) { - grpc_byte_stream_pull(exec_ctx, - calld->send_op->payload->send_message.send_message, - &calld->incoming_slice); - grpc_slice_buffer_add(&calld->slices, calld->incoming_slice); - if (calld->send_length == calld->slices.length) { + exec_ctx, calld->send_message_batch->payload->send_message.send_message, + ~(size_t)0, &calld->on_send_message_next_done)) { + grpc_error *error = pull_slice_from_send_message(exec_ctx, calld); + if (error != GRPC_ERROR_NONE) return error; + if (calld->slices.length == + calld->send_message_batch->payload->send_message.send_message->length) { finish_send_message(exec_ctx, elem); break; } } + return GRPC_ERROR_NONE; } -static void handle_send_message_batch(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem, - grpc_transport_stream_op_batch *op, - bool has_compression_algorithm) { - call_data *calld = elem->call_data; - if (!skip_compression(elem, op->payload->send_message.send_message->flags, +// Async callback for grpc_byte_stream_next(). +static void on_send_message_next_done(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + grpc_call_element *elem = (grpc_call_element *)arg; + call_data *calld = (call_data *)elem->call_data; + if (error != GRPC_ERROR_NONE) goto fail; + error = pull_slice_from_send_message(exec_ctx, calld); + if (error != GRPC_ERROR_NONE) goto fail; + if (calld->slices.length == + calld->send_message_batch->payload->send_message.send_message->length) { + finish_send_message(exec_ctx, elem); + } else { + // This will either finish reading all of the data and invoke + // finish_send_message(), or else it will make an async call to + // grpc_byte_stream_next(), which will eventually result in calling + // this function again. + error = continue_reading_send_message(exec_ctx, elem); + if (error != GRPC_ERROR_NONE) goto fail; + } + return; +fail: + grpc_transport_stream_op_batch_finish_with_failure( + exec_ctx, calld->send_message_batch, error); +} + +static void start_send_message_batch(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem, + grpc_transport_stream_op_batch *batch, + bool has_compression_algorithm) { + call_data *calld = (call_data *)elem->call_data; + if (!skip_compression(elem, batch->payload->send_message.send_message->flags, has_compression_algorithm)) { - calld->send_op = op; - calld->send_length = op->payload->send_message.send_message->length; - calld->send_flags = op->payload->send_message.send_message->flags; - continue_send_message(exec_ctx, elem); + calld->send_message_batch = batch; + // This will either finish reading all of the data and invoke + // finish_send_message(), or else it will make an async call to + // grpc_byte_stream_next(), which will eventually result in calling + // on_send_message_next_done(). + grpc_error *error = continue_reading_send_message(exec_ctx, elem); + if (error != GRPC_ERROR_NONE) { + grpc_transport_stream_op_batch_finish_with_failure( + exec_ctx, calld->send_message_batch, error); + } } else { /* pass control down the stack */ - grpc_call_next_op(exec_ctx, elem, op); + grpc_call_next_op(exec_ctx, elem, batch); } } static void compress_start_transport_stream_op_batch( grpc_exec_ctx *exec_ctx, grpc_call_element *elem, - grpc_transport_stream_op_batch *op) { + grpc_transport_stream_op_batch *batch) { call_data *calld = elem->call_data; GPR_TIMER_BEGIN("compress_start_transport_stream_op_batch", 0); - if (op->cancel_stream) { - GRPC_ERROR_REF(op->payload->cancel_stream.cancel_error); + if (batch->cancel_stream) { + // TODO(roth): As part of the upcoming call combiner work, change + // this to call grpc_byte_stream_shutdown() on the incoming byte + // stream, to cancel any in-flight calls to grpc_byte_stream_next(). + GRPC_ERROR_REF(batch->payload->cancel_stream.cancel_error); gpr_atm cur = gpr_atm_full_xchg( &calld->send_initial_metadata_state, - CANCELLED_BIT | (gpr_atm)op->payload->cancel_stream.cancel_error); + CANCELLED_BIT | (gpr_atm)batch->payload->cancel_stream.cancel_error); switch (cur) { case HAS_COMPRESSION_ALGORITHM: case NO_COMPRESSION_ALGORITHM: @@ -293,7 +326,7 @@ static void compress_start_transport_stream_op_batch( if ((cur & CANCELLED_BIT) == 0) { grpc_transport_stream_op_batch_finish_with_failure( exec_ctx, (grpc_transport_stream_op_batch *)cur, - GRPC_ERROR_REF(op->payload->cancel_stream.cancel_error)); + GRPC_ERROR_REF(batch->payload->cancel_stream.cancel_error)); } else { GRPC_ERROR_UNREF((grpc_error *)(cur & ~CANCELLED_BIT)); } @@ -301,14 +334,15 @@ static void compress_start_transport_stream_op_batch( } } - if (op->send_initial_metadata) { + if (batch->send_initial_metadata) { bool has_compression_algorithm; grpc_error *error = process_send_initial_metadata( exec_ctx, elem, - op->payload->send_initial_metadata.send_initial_metadata, + batch->payload->send_initial_metadata.send_initial_metadata, &has_compression_algorithm); if (error != GRPC_ERROR_NONE) { - grpc_transport_stream_op_batch_finish_with_failure(exec_ctx, op, error); + grpc_transport_stream_op_batch_finish_with_failure(exec_ctx, batch, + error); return; } gpr_atm cur; @@ -324,32 +358,32 @@ static void compress_start_transport_stream_op_batch( goto retry_send_im; } if (cur != INITIAL_METADATA_UNSEEN) { - handle_send_message_batch(exec_ctx, elem, - (grpc_transport_stream_op_batch *)cur, - has_compression_algorithm); + start_send_message_batch(exec_ctx, elem, + (grpc_transport_stream_op_batch *)cur, + has_compression_algorithm); } } } - if (op->send_message) { + if (batch->send_message) { gpr_atm cur; retry_send: cur = gpr_atm_acq_load(&calld->send_initial_metadata_state); switch (cur) { case INITIAL_METADATA_UNSEEN: if (!gpr_atm_rel_cas(&calld->send_initial_metadata_state, cur, - (gpr_atm)op)) { + (gpr_atm)batch)) { goto retry_send; } break; case HAS_COMPRESSION_ALGORITHM: case NO_COMPRESSION_ALGORITHM: - handle_send_message_batch(exec_ctx, elem, op, - cur == HAS_COMPRESSION_ALGORITHM); + start_send_message_batch(exec_ctx, elem, batch, + cur == HAS_COMPRESSION_ALGORITHM); break; default: if (cur & CANCELLED_BIT) { grpc_transport_stream_op_batch_finish_with_failure( - exec_ctx, op, + exec_ctx, batch, GRPC_ERROR_REF((grpc_error *)(cur & ~CANCELLED_BIT))); } else { /* >1 send_message concurrently */ @@ -358,7 +392,7 @@ static void compress_start_transport_stream_op_batch( } } else { /* pass control down the stack */ - grpc_call_next_op(exec_ctx, elem, op); + grpc_call_next_op(exec_ctx, elem, batch); } GPR_TIMER_END("compress_start_transport_stream_op_batch", 0); @@ -373,10 +407,10 @@ static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx, /* initialize members */ grpc_slice_buffer_init(&calld->slices); - GRPC_CLOSURE_INIT(&calld->got_slice, got_slice, elem, - grpc_schedule_on_exec_ctx); - GRPC_CLOSURE_INIT(&calld->send_done, send_done, elem, - grpc_schedule_on_exec_ctx); + GRPC_CLOSURE_INIT(&calld->on_send_message_next_done, + on_send_message_next_done, elem, grpc_schedule_on_exec_ctx); + GRPC_CLOSURE_INIT(&calld->send_message_on_complete, send_message_on_complete, + elem, grpc_schedule_on_exec_ctx); return GRPC_ERROR_NONE; } diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c index 731ebf400f7..b1a76988110 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c @@ -1173,6 +1173,7 @@ static void continue_fetching_send_locked(grpc_exec_ctx *exec_ctx, return; /* early out */ } if (s->fetched_send_message_length == s->fetching_send_message->length) { + grpc_byte_stream_destroy(exec_ctx, s->fetching_send_message); int64_t notify_offset = s->next_message_end_offset; if (notify_offset <= s->flow_controlled_bytes_written) { grpc_chttp2_complete_closure_step( @@ -1195,9 +1196,14 @@ static void continue_fetching_send_locked(grpc_exec_ctx *exec_ctx, return; /* early out */ } else if (grpc_byte_stream_next(exec_ctx, s->fetching_send_message, UINT32_MAX, &s->complete_fetch_locked)) { - grpc_byte_stream_pull(exec_ctx, s->fetching_send_message, - &s->fetching_slice); - add_fetched_slice_locked(exec_ctx, t, s); + grpc_error *error = grpc_byte_stream_pull( + exec_ctx, s->fetching_send_message, &s->fetching_slice); + if (error != GRPC_ERROR_NONE) { + grpc_byte_stream_destroy(exec_ctx, s->fetching_send_message); + grpc_chttp2_cancel_stream(exec_ctx, t, s, error); + } else { + add_fetched_slice_locked(exec_ctx, t, s); + } } } } @@ -1214,10 +1220,9 @@ static void complete_fetch_locked(grpc_exec_ctx *exec_ctx, void *gs, continue_fetching_send_locked(exec_ctx, t, s); } } - if (error != GRPC_ERROR_NONE) { - /* TODO(ctiller): what to do here */ - abort(); + grpc_byte_stream_destroy(exec_ctx, s->fetching_send_message); + grpc_chttp2_cancel_stream(exec_ctx, t, s, error); } } @@ -2686,22 +2691,9 @@ static grpc_error *incoming_byte_stream_pull(grpc_exec_ctx *exec_ctx, return GRPC_ERROR_NONE; } -static void incoming_byte_stream_destroy(grpc_exec_ctx *exec_ctx, - grpc_byte_stream *byte_stream); - static void incoming_byte_stream_destroy_locked(grpc_exec_ctx *exec_ctx, void *byte_stream, - grpc_error *error_ignored) { - grpc_chttp2_incoming_byte_stream *bs = byte_stream; - grpc_chttp2_stream *s = bs->stream; - grpc_chttp2_transport *t = s->t; - - GPR_ASSERT(bs->base.destroy == incoming_byte_stream_destroy); - incoming_byte_stream_unref(exec_ctx, bs); - s->pending_byte_stream = false; - grpc_chttp2_maybe_complete_recv_message(exec_ctx, t, s); - grpc_chttp2_maybe_complete_recv_trailing_metadata(exec_ctx, t, s); -} + grpc_error *error_ignored); static void incoming_byte_stream_destroy(grpc_exec_ctx *exec_ctx, grpc_byte_stream *byte_stream) { @@ -2768,6 +2760,33 @@ grpc_error *grpc_chttp2_incoming_byte_stream_finished( return error; } +static void incoming_byte_stream_shutdown(grpc_exec_ctx *exec_ctx, + grpc_byte_stream *byte_stream, + grpc_error *error) { + grpc_chttp2_incoming_byte_stream *bs = + (grpc_chttp2_incoming_byte_stream *)byte_stream; + GRPC_ERROR_UNREF(grpc_chttp2_incoming_byte_stream_finished( + exec_ctx, bs, error, true /* reset_on_error */)); +} + +static const grpc_byte_stream_vtable grpc_chttp2_incoming_byte_stream_vtable = { + incoming_byte_stream_next, incoming_byte_stream_pull, + incoming_byte_stream_shutdown, incoming_byte_stream_destroy}; + +static void incoming_byte_stream_destroy_locked(grpc_exec_ctx *exec_ctx, + void *byte_stream, + grpc_error *error_ignored) { + grpc_chttp2_incoming_byte_stream *bs = byte_stream; + grpc_chttp2_stream *s = bs->stream; + grpc_chttp2_transport *t = s->t; + + GPR_ASSERT(bs->base.vtable == &grpc_chttp2_incoming_byte_stream_vtable); + incoming_byte_stream_unref(exec_ctx, bs); + s->pending_byte_stream = false; + grpc_chttp2_maybe_complete_recv_message(exec_ctx, t, s); + grpc_chttp2_maybe_complete_recv_trailing_metadata(exec_ctx, t, s); +} + grpc_chttp2_incoming_byte_stream *grpc_chttp2_incoming_byte_stream_create( grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_chttp2_stream *s, uint32_t frame_size, uint32_t flags) { @@ -2776,9 +2795,7 @@ grpc_chttp2_incoming_byte_stream *grpc_chttp2_incoming_byte_stream_create( incoming_byte_stream->base.length = frame_size; incoming_byte_stream->remaining_bytes = frame_size; incoming_byte_stream->base.flags = flags; - incoming_byte_stream->base.next = incoming_byte_stream_next; - incoming_byte_stream->base.pull = incoming_byte_stream_pull; - incoming_byte_stream->base.destroy = incoming_byte_stream_destroy; + incoming_byte_stream->base.vtable = &grpc_chttp2_incoming_byte_stream_vtable; gpr_ref_init(&incoming_byte_stream->refs, 2); incoming_byte_stream->transport = t; incoming_byte_stream->stream = s; diff --git a/src/core/ext/transport/inproc/inproc_transport.c b/src/core/ext/transport/inproc/inproc_transport.c index 14498021ebd..6f4b429ee2f 100644 --- a/src/core/ext/transport/inproc/inproc_transport.c +++ b/src/core/ext/transport/inproc/inproc_transport.c @@ -72,6 +72,7 @@ typedef struct sb_list_entry { typedef struct { grpc_byte_stream base; sb_list_entry *le; + grpc_error *shutdown_error; } inproc_slice_byte_stream; typedef struct { @@ -201,24 +202,39 @@ static grpc_error *inproc_slice_byte_stream_pull(grpc_exec_ctx *exec_ctx, grpc_byte_stream *bs, grpc_slice *slice) { inproc_slice_byte_stream *stream = (inproc_slice_byte_stream *)bs; + if (stream->shutdown_error != GRPC_ERROR_NONE) { + return GRPC_ERROR_REF(stream->shutdown_error); + } *slice = grpc_slice_buffer_take_first(&stream->le->sb); return GRPC_ERROR_NONE; } +static void inproc_slice_byte_stream_shutdown(grpc_exec_ctx *exec_ctx, + grpc_byte_stream *bs, + grpc_error *error) { + inproc_slice_byte_stream *stream = (inproc_slice_byte_stream *)bs; + GRPC_ERROR_UNREF(stream->shutdown_error); + stream->shutdown_error = error; +} + static void inproc_slice_byte_stream_destroy(grpc_exec_ctx *exec_ctx, grpc_byte_stream *bs) { inproc_slice_byte_stream *stream = (inproc_slice_byte_stream *)bs; sb_list_entry_destroy(exec_ctx, stream->le); + GRPC_ERROR_UNREF(stream->shutdown_error); } +static const grpc_byte_stream_vtable inproc_slice_byte_stream_vtable = { + inproc_slice_byte_stream_next, inproc_slice_byte_stream_pull, + inproc_slice_byte_stream_shutdown, inproc_slice_byte_stream_destroy}; + void inproc_slice_byte_stream_init(inproc_slice_byte_stream *s, sb_list_entry *le) { s->base.length = (uint32_t)le->sb.length; s->base.flags = 0; - s->base.next = inproc_slice_byte_stream_next; - s->base.pull = inproc_slice_byte_stream_pull; - s->base.destroy = inproc_slice_byte_stream_destroy; + s->base.vtable = &inproc_slice_byte_stream_vtable; s->le = le; + s->shutdown_error = GRPC_ERROR_NONE; } static void ref_transport(inproc_transport *t) { @@ -956,11 +972,18 @@ static void perform_stream_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt, GPR_ASSERT(grpc_byte_stream_next(exec_ctx, op->payload->send_message.send_message, SIZE_MAX, &unused)); - grpc_byte_stream_pull(exec_ctx, op->payload->send_message.send_message, - &message_slice); + error = grpc_byte_stream_pull( + exec_ctx, op->payload->send_message.send_message, &message_slice); + if (error != GRPC_ERROR_NONE) { + cancel_stream_locked(exec_ctx, s, GRPC_ERROR_REF(error)); + break; + } + GPR_ASSERT(error == GRPC_ERROR_NONE); remaining -= GRPC_SLICE_LENGTH(message_slice); grpc_slice_buffer_add(dest, message_slice); } while (remaining != 0); + grpc_byte_stream_destroy(exec_ctx, + op->payload->send_message.send_message); } if (error == GRPC_ERROR_NONE && op->send_trailing_metadata) { grpc_metadata_batch *dest = (other == NULL) ? &s->write_buffer_trailing_md diff --git a/src/core/lib/transport/byte_stream.c b/src/core/lib/transport/byte_stream.c index 3355814017f..fb03a10315b 100644 --- a/src/core/lib/transport/byte_stream.c +++ b/src/core/lib/transport/byte_stream.c @@ -19,29 +19,37 @@ #include "src/core/lib/transport/byte_stream.h" #include +#include #include #include "src/core/lib/slice/slice_internal.h" -int grpc_byte_stream_next(grpc_exec_ctx *exec_ctx, - grpc_byte_stream *byte_stream, size_t max_size_hint, - grpc_closure *on_complete) { - return byte_stream->next(exec_ctx, byte_stream, max_size_hint, on_complete); +bool grpc_byte_stream_next(grpc_exec_ctx *exec_ctx, + grpc_byte_stream *byte_stream, size_t max_size_hint, + grpc_closure *on_complete) { + return byte_stream->vtable->next(exec_ctx, byte_stream, max_size_hint, + on_complete); } grpc_error *grpc_byte_stream_pull(grpc_exec_ctx *exec_ctx, grpc_byte_stream *byte_stream, grpc_slice *slice) { - return byte_stream->pull(exec_ctx, byte_stream, slice); + return byte_stream->vtable->pull(exec_ctx, byte_stream, slice); +} + +void grpc_byte_stream_shutdown(grpc_exec_ctx *exec_ctx, + grpc_byte_stream *byte_stream, + grpc_error *error) { + byte_stream->vtable->shutdown(exec_ctx, byte_stream, error); } void grpc_byte_stream_destroy(grpc_exec_ctx *exec_ctx, grpc_byte_stream *byte_stream) { - byte_stream->destroy(exec_ctx, byte_stream); + byte_stream->vtable->destroy(exec_ctx, byte_stream); } -/* slice_buffer_stream */ +// grpc_slice_buffer_stream static bool slice_buffer_stream_next(grpc_exec_ctx *exec_ctx, grpc_byte_stream *byte_stream, @@ -56,6 +64,9 @@ static grpc_error *slice_buffer_stream_pull(grpc_exec_ctx *exec_ctx, grpc_byte_stream *byte_stream, grpc_slice *slice) { grpc_slice_buffer_stream *stream = (grpc_slice_buffer_stream *)byte_stream; + if (stream->shutdown_error != GRPC_ERROR_NONE) { + return GRPC_ERROR_REF(stream->shutdown_error); + } GPR_ASSERT(stream->cursor < stream->backing_buffer->count); *slice = grpc_slice_ref_internal(stream->backing_buffer->slices[stream->cursor]); @@ -63,8 +74,23 @@ static grpc_error *slice_buffer_stream_pull(grpc_exec_ctx *exec_ctx, return GRPC_ERROR_NONE; } +static void slice_buffer_stream_shutdown(grpc_exec_ctx *exec_ctx, + grpc_byte_stream *byte_stream, + grpc_error *error) { + grpc_slice_buffer_stream *stream = (grpc_slice_buffer_stream *)byte_stream; + GRPC_ERROR_UNREF(stream->shutdown_error); + stream->shutdown_error = error; +} + static void slice_buffer_stream_destroy(grpc_exec_ctx *exec_ctx, - grpc_byte_stream *byte_stream) {} + grpc_byte_stream *byte_stream) { + grpc_slice_buffer_stream *stream = (grpc_slice_buffer_stream *)byte_stream; + GRPC_ERROR_UNREF(stream->shutdown_error); +} + +static const grpc_byte_stream_vtable slice_buffer_stream_vtable = { + slice_buffer_stream_next, slice_buffer_stream_pull, + slice_buffer_stream_shutdown, slice_buffer_stream_destroy}; void grpc_slice_buffer_stream_init(grpc_slice_buffer_stream *stream, grpc_slice_buffer *slice_buffer, @@ -72,9 +98,89 @@ void grpc_slice_buffer_stream_init(grpc_slice_buffer_stream *stream, GPR_ASSERT(slice_buffer->length <= UINT32_MAX); stream->base.length = (uint32_t)slice_buffer->length; stream->base.flags = flags; - stream->base.next = slice_buffer_stream_next; - stream->base.pull = slice_buffer_stream_pull; - stream->base.destroy = slice_buffer_stream_destroy; + stream->base.vtable = &slice_buffer_stream_vtable; stream->backing_buffer = slice_buffer; stream->cursor = 0; + stream->shutdown_error = GRPC_ERROR_NONE; +} + +// grpc_caching_byte_stream + +void grpc_byte_stream_cache_init(grpc_byte_stream_cache *cache, + grpc_byte_stream *underlying_stream) { + cache->underlying_stream = underlying_stream; + grpc_slice_buffer_init(&cache->cache_buffer); +} + +void grpc_byte_stream_cache_destroy(grpc_exec_ctx *exec_ctx, + grpc_byte_stream_cache *cache) { + grpc_byte_stream_destroy(exec_ctx, cache->underlying_stream); + grpc_slice_buffer_destroy_internal(exec_ctx, &cache->cache_buffer); +} + +static bool caching_byte_stream_next(grpc_exec_ctx *exec_ctx, + grpc_byte_stream *byte_stream, + size_t max_size_hint, + grpc_closure *on_complete) { + grpc_caching_byte_stream *stream = (grpc_caching_byte_stream *)byte_stream; + if (stream->shutdown_error != GRPC_ERROR_NONE) return true; + if (stream->cursor < stream->cache->cache_buffer.count) return true; + return grpc_byte_stream_next(exec_ctx, stream->cache->underlying_stream, + max_size_hint, on_complete); +} + +static grpc_error *caching_byte_stream_pull(grpc_exec_ctx *exec_ctx, + grpc_byte_stream *byte_stream, + grpc_slice *slice) { + grpc_caching_byte_stream *stream = (grpc_caching_byte_stream *)byte_stream; + if (stream->shutdown_error != GRPC_ERROR_NONE) { + return GRPC_ERROR_REF(stream->shutdown_error); + } + if (stream->cursor < stream->cache->cache_buffer.count) { + *slice = grpc_slice_ref_internal( + stream->cache->cache_buffer.slices[stream->cursor]); + ++stream->cursor; + return GRPC_ERROR_NONE; + } + grpc_error *error = + grpc_byte_stream_pull(exec_ctx, stream->cache->underlying_stream, slice); + if (error == GRPC_ERROR_NONE) { + ++stream->cursor; + grpc_slice_buffer_add(&stream->cache->cache_buffer, + grpc_slice_ref_internal(*slice)); + } + return error; +} + +static void caching_byte_stream_shutdown(grpc_exec_ctx *exec_ctx, + grpc_byte_stream *byte_stream, + grpc_error *error) { + grpc_caching_byte_stream *stream = (grpc_caching_byte_stream *)byte_stream; + GRPC_ERROR_UNREF(stream->shutdown_error); + stream->shutdown_error = GRPC_ERROR_REF(error); + grpc_byte_stream_shutdown(exec_ctx, stream->cache->underlying_stream, error); +} + +static void caching_byte_stream_destroy(grpc_exec_ctx *exec_ctx, + grpc_byte_stream *byte_stream) { + grpc_caching_byte_stream *stream = (grpc_caching_byte_stream *)byte_stream; + GRPC_ERROR_UNREF(stream->shutdown_error); +} + +static const grpc_byte_stream_vtable caching_byte_stream_vtable = { + caching_byte_stream_next, caching_byte_stream_pull, + caching_byte_stream_shutdown, caching_byte_stream_destroy}; + +void grpc_caching_byte_stream_init(grpc_caching_byte_stream *stream, + grpc_byte_stream_cache *cache) { + memset(stream, 0, sizeof(*stream)); + stream->base.length = cache->underlying_stream->length; + stream->base.flags = cache->underlying_stream->flags; + stream->base.vtable = &caching_byte_stream_vtable; + stream->cache = cache; + stream->shutdown_error = GRPC_ERROR_NONE; +} + +void grpc_caching_byte_stream_reset(grpc_caching_byte_stream *stream) { + stream->cursor = 0; } diff --git a/src/core/lib/transport/byte_stream.h b/src/core/lib/transport/byte_stream.h index f172296e4b4..1e1e8310b83 100644 --- a/src/core/lib/transport/byte_stream.h +++ b/src/core/lib/transport/byte_stream.h @@ -28,52 +28,109 @@ /** Mask of all valid internal flags. */ #define GRPC_WRITE_INTERNAL_USED_MASK (GRPC_WRITE_INTERNAL_COMPRESS) -struct grpc_byte_stream; typedef struct grpc_byte_stream grpc_byte_stream; -struct grpc_byte_stream { - uint32_t length; - uint32_t flags; +typedef struct { bool (*next)(grpc_exec_ctx *exec_ctx, grpc_byte_stream *byte_stream, size_t max_size_hint, grpc_closure *on_complete); grpc_error *(*pull)(grpc_exec_ctx *exec_ctx, grpc_byte_stream *byte_stream, grpc_slice *slice); + void (*shutdown)(grpc_exec_ctx *exec_ctx, grpc_byte_stream *byte_stream, + grpc_error *error); void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_byte_stream *byte_stream); +} grpc_byte_stream_vtable; + +struct grpc_byte_stream { + uint32_t length; + uint32_t flags; + const grpc_byte_stream_vtable *vtable; }; -/* returns 1 if the bytes are available immediately (in which case - * on_complete will not be called), 0 if the bytes will be available - * asynchronously. - * - * max_size_hint can be set as a hint as to the maximum number - * of bytes that would be acceptable to read. - */ -int grpc_byte_stream_next(grpc_exec_ctx *exec_ctx, - grpc_byte_stream *byte_stream, size_t max_size_hint, - grpc_closure *on_complete); +// Returns true if the bytes are available immediately (in which case +// on_complete will not be called), false if the bytes will be available +// asynchronously. +// +// max_size_hint can be set as a hint as to the maximum number +// of bytes that would be acceptable to read. +bool grpc_byte_stream_next(grpc_exec_ctx *exec_ctx, + grpc_byte_stream *byte_stream, size_t max_size_hint, + grpc_closure *on_complete); -/* returns the next slice in the byte stream when it is ready (indicated by - * either grpc_byte_stream_next returning 1 or on_complete passed to - * grpc_byte_stream_next is called). - * - * once a slice is returned into *slice, it is owned by the caller. - */ +// Returns the next slice in the byte stream when it is ready (indicated by +// either grpc_byte_stream_next returning true or on_complete passed to +// grpc_byte_stream_next is called). +// +// Once a slice is returned into *slice, it is owned by the caller. grpc_error *grpc_byte_stream_pull(grpc_exec_ctx *exec_ctx, grpc_byte_stream *byte_stream, grpc_slice *slice); +// Shuts down the byte stream. +// +// If there is a pending call to on_complete from grpc_byte_stream_next(), +// it will be invoked with the error passed to grpc_byte_stream_shutdown(). +// +// The next call to grpc_byte_stream_pull() (if any) will return the error +// passed to grpc_byte_stream_shutdown(). +void grpc_byte_stream_shutdown(grpc_exec_ctx *exec_ctx, + grpc_byte_stream *byte_stream, + grpc_error *error); + void grpc_byte_stream_destroy(grpc_exec_ctx *exec_ctx, grpc_byte_stream *byte_stream); -/* grpc_byte_stream that wraps a slice buffer */ +// grpc_slice_buffer_stream +// +// A grpc_byte_stream that wraps a slice buffer. + typedef struct grpc_slice_buffer_stream { grpc_byte_stream base; grpc_slice_buffer *backing_buffer; size_t cursor; + grpc_error *shutdown_error; } grpc_slice_buffer_stream; void grpc_slice_buffer_stream_init(grpc_slice_buffer_stream *stream, grpc_slice_buffer *slice_buffer, uint32_t flags); +// grpc_caching_byte_stream +// +// A grpc_byte_stream that that wraps an underlying byte stream but caches +// the resulting slices in a slice buffer. If an initial attempt fails +// without fully draining the underlying stream, a new caching stream +// can be created from the same underlying cache, in which case it will +// return whatever is in the backing buffer before continuing to read the +// underlying stream. +// +// NOTE: No synchronization is done, so it is not safe to have multiple +// grpc_caching_byte_streams simultaneously drawing from the same underlying +// grpc_byte_stream_cache at the same time. + +typedef struct { + grpc_byte_stream *underlying_stream; + grpc_slice_buffer cache_buffer; +} grpc_byte_stream_cache; + +// Takes ownership of underlying_stream. +void grpc_byte_stream_cache_init(grpc_byte_stream_cache *cache, + grpc_byte_stream *underlying_stream); + +// Must not be called while still in use by a grpc_caching_byte_stream. +void grpc_byte_stream_cache_destroy(grpc_exec_ctx *exec_ctx, + grpc_byte_stream_cache *cache); + +typedef struct { + grpc_byte_stream base; + grpc_byte_stream_cache *cache; + size_t cursor; + grpc_error *shutdown_error; +} grpc_caching_byte_stream; + +void grpc_caching_byte_stream_init(grpc_caching_byte_stream *stream, + grpc_byte_stream_cache *cache); + +// Resets the byte stream to the start of the underlying stream. +void grpc_caching_byte_stream_reset(grpc_caching_byte_stream *stream); + #endif /* GRPC_CORE_LIB_TRANSPORT_BYTE_STREAM_H */ diff --git a/src/core/lib/transport/transport.c b/src/core/lib/transport/transport.c index 7281602d66b..6c61f4b8d9d 100644 --- a/src/core/lib/transport/transport.c +++ b/src/core/lib/transport/transport.c @@ -207,27 +207,35 @@ grpc_endpoint *grpc_transport_get_endpoint(grpc_exec_ctx *exec_ctx, return transport->vtable->get_endpoint(exec_ctx, transport); } +// This comment should be sung to the tune of +// "Supercalifragilisticexpialidocious": +// // grpc_transport_stream_op_batch_finish_with_failure // is a function that must always unref cancel_error // though it lives in lib, it handles transport stream ops sure // it's grpc_transport_stream_op_batch_finish_with_failure void grpc_transport_stream_op_batch_finish_with_failure( - grpc_exec_ctx *exec_ctx, grpc_transport_stream_op_batch *op, + grpc_exec_ctx *exec_ctx, grpc_transport_stream_op_batch *batch, grpc_error *error) { - if (op->recv_message) { - GRPC_CLOSURE_SCHED(exec_ctx, op->payload->recv_message.recv_message_ready, + if (batch->send_message) { + grpc_byte_stream_destroy(exec_ctx, + batch->payload->send_message.send_message); + } + if (batch->recv_message) { + GRPC_CLOSURE_SCHED(exec_ctx, + batch->payload->recv_message.recv_message_ready, GRPC_ERROR_REF(error)); } - if (op->recv_initial_metadata) { + if (batch->recv_initial_metadata) { GRPC_CLOSURE_SCHED( exec_ctx, - op->payload->recv_initial_metadata.recv_initial_metadata_ready, + batch->payload->recv_initial_metadata.recv_initial_metadata_ready, GRPC_ERROR_REF(error)); } - GRPC_CLOSURE_SCHED(exec_ctx, op->on_complete, error); - if (op->cancel_stream) { - GRPC_ERROR_UNREF(op->payload->cancel_stream.cancel_error); + GRPC_CLOSURE_SCHED(exec_ctx, batch->on_complete, error); + if (batch->cancel_stream) { + GRPC_ERROR_UNREF(batch->payload->cancel_stream.cancel_error); } } diff --git a/src/core/lib/transport/transport.h b/src/core/lib/transport/transport.h index 84e53e683ac..099138ea146 100644 --- a/src/core/lib/transport/transport.h +++ b/src/core/lib/transport/transport.h @@ -159,6 +159,11 @@ struct grpc_transport_stream_op_batch_payload { } send_trailing_metadata; struct { + // The transport (or a filter that decides to return a failure before + // the op gets down to the transport) is responsible for calling + // grpc_byte_stream_destroy() on this. + // The batch's on_complete will not be called until after the byte + // stream is destroyed. grpc_byte_stream *send_message; } send_message; @@ -174,6 +179,10 @@ struct grpc_transport_stream_op_batch_payload { } recv_initial_metadata; struct { + // Will be set by the transport to point to the byte stream + // containing a received message. + // The caller is responsible for calling grpc_byte_stream_destroy() + // on this byte stream. grpc_byte_stream **recv_message; /** Should be enqueued when one message is ready to be processed. */ grpc_closure *recv_message_ready; diff --git a/test/core/transport/BUILD b/test/core/transport/BUILD index 8091cf9c633..040c0c35c22 100644 --- a/test/core/transport/BUILD +++ b/test/core/transport/BUILD @@ -35,6 +35,18 @@ grpc_cc_test( ], ) +grpc_cc_test( + name = "byte_stream_test", + srcs = ["byte_stream_test.c"], + language = "C", + deps = [ + "//:gpr", + "//:grpc", + "//test/core/util:gpr_test_util", + "//test/core/util:grpc_test_util", + ], +) + grpc_cc_test( name = "connectivity_state_test", srcs = ["connectivity_state_test.c"], diff --git a/test/core/transport/byte_stream_test.c b/test/core/transport/byte_stream_test.c new file mode 100644 index 00000000000..a0c5f961cfd --- /dev/null +++ b/test/core/transport/byte_stream_test.c @@ -0,0 +1,279 @@ +/* + * + * Copyright 2017 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "src/core/lib/transport/byte_stream.h" + +#include +#include +#include + +#include "src/core/lib/slice/slice_internal.h" + +#include "test/core/util/test_config.h" + +// +// grpc_slice_buffer_stream tests +// + +static void not_called_closure(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + GPR_ASSERT(false); +} + +static void test_slice_buffer_stream_basic(void) { + gpr_log(GPR_DEBUG, "test_slice_buffer_stream_basic"); + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + // Create and populate slice buffer. + grpc_slice_buffer buffer; + grpc_slice_buffer_init(&buffer); + grpc_slice input[] = { + grpc_slice_from_static_string("foo"), + grpc_slice_from_static_string("bar"), + }; + for (size_t i = 0; i < GPR_ARRAY_SIZE(input); ++i) { + grpc_slice_buffer_add(&buffer, input[i]); + } + // Create byte stream. + grpc_slice_buffer_stream stream; + grpc_slice_buffer_stream_init(&stream, &buffer, 0); + GPR_ASSERT(stream.base.length == 6); + grpc_closure closure; + GRPC_CLOSURE_INIT(&closure, not_called_closure, NULL, + grpc_schedule_on_exec_ctx); + // Read each slice. Note that next() always returns synchronously. + for (size_t i = 0; i < GPR_ARRAY_SIZE(input); ++i) { + GPR_ASSERT( + grpc_byte_stream_next(&exec_ctx, &stream.base, ~(size_t)0, &closure)); + grpc_slice output; + grpc_error *error = grpc_byte_stream_pull(&exec_ctx, &stream.base, &output); + GPR_ASSERT(error == GRPC_ERROR_NONE); + GPR_ASSERT(grpc_slice_eq(input[i], output)); + grpc_slice_unref_internal(&exec_ctx, output); + } + // Clean up. + grpc_byte_stream_destroy(&exec_ctx, &stream.base); + grpc_slice_buffer_destroy_internal(&exec_ctx, &buffer); + grpc_exec_ctx_finish(&exec_ctx); +} + +static void test_slice_buffer_stream_shutdown(void) { + gpr_log(GPR_DEBUG, "test_slice_buffer_stream_shutdown"); + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + // Create and populate slice buffer. + grpc_slice_buffer buffer; + grpc_slice_buffer_init(&buffer); + grpc_slice input[] = { + grpc_slice_from_static_string("foo"), + grpc_slice_from_static_string("bar"), + }; + for (size_t i = 0; i < GPR_ARRAY_SIZE(input); ++i) { + grpc_slice_buffer_add(&buffer, input[i]); + } + // Create byte stream. + grpc_slice_buffer_stream stream; + grpc_slice_buffer_stream_init(&stream, &buffer, 0); + GPR_ASSERT(stream.base.length == 6); + grpc_closure closure; + GRPC_CLOSURE_INIT(&closure, not_called_closure, NULL, + grpc_schedule_on_exec_ctx); + // Read the first slice. + GPR_ASSERT( + grpc_byte_stream_next(&exec_ctx, &stream.base, ~(size_t)0, &closure)); + grpc_slice output; + grpc_error *error = grpc_byte_stream_pull(&exec_ctx, &stream.base, &output); + GPR_ASSERT(error == GRPC_ERROR_NONE); + GPR_ASSERT(grpc_slice_eq(input[0], output)); + grpc_slice_unref_internal(&exec_ctx, output); + // Now shutdown. + grpc_error *shutdown_error = + GRPC_ERROR_CREATE_FROM_STATIC_STRING("shutdown error"); + grpc_byte_stream_shutdown(&exec_ctx, &stream.base, + GRPC_ERROR_REF(shutdown_error)); + // After shutdown, the next pull() should return the error. + GPR_ASSERT( + grpc_byte_stream_next(&exec_ctx, &stream.base, ~(size_t)0, &closure)); + error = grpc_byte_stream_pull(&exec_ctx, &stream.base, &output); + GPR_ASSERT(error == shutdown_error); + GRPC_ERROR_UNREF(error); + GRPC_ERROR_UNREF(shutdown_error); + // Clean up. + grpc_byte_stream_destroy(&exec_ctx, &stream.base); + grpc_slice_buffer_destroy_internal(&exec_ctx, &buffer); + grpc_exec_ctx_finish(&exec_ctx); +} + +// +// grpc_caching_byte_stream tests +// + +static void test_caching_byte_stream_basic(void) { + gpr_log(GPR_DEBUG, "test_caching_byte_stream_basic"); + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + // Create and populate slice buffer byte stream. + grpc_slice_buffer buffer; + grpc_slice_buffer_init(&buffer); + grpc_slice input[] = { + grpc_slice_from_static_string("foo"), + grpc_slice_from_static_string("bar"), + }; + for (size_t i = 0; i < GPR_ARRAY_SIZE(input); ++i) { + grpc_slice_buffer_add(&buffer, input[i]); + } + grpc_slice_buffer_stream underlying_stream; + grpc_slice_buffer_stream_init(&underlying_stream, &buffer, 0); + // Create cache and caching stream. + grpc_byte_stream_cache cache; + grpc_byte_stream_cache_init(&cache, &underlying_stream.base); + grpc_caching_byte_stream stream; + grpc_caching_byte_stream_init(&stream, &cache); + grpc_closure closure; + GRPC_CLOSURE_INIT(&closure, not_called_closure, NULL, + grpc_schedule_on_exec_ctx); + // Read each slice. Note that next() always returns synchronously, + // because the underlying byte stream always does. + for (size_t i = 0; i < GPR_ARRAY_SIZE(input); ++i) { + GPR_ASSERT( + grpc_byte_stream_next(&exec_ctx, &stream.base, ~(size_t)0, &closure)); + grpc_slice output; + grpc_error *error = grpc_byte_stream_pull(&exec_ctx, &stream.base, &output); + GPR_ASSERT(error == GRPC_ERROR_NONE); + GPR_ASSERT(grpc_slice_eq(input[i], output)); + grpc_slice_unref_internal(&exec_ctx, output); + } + // Clean up. + grpc_byte_stream_destroy(&exec_ctx, &stream.base); + grpc_byte_stream_cache_destroy(&exec_ctx, &cache); + grpc_slice_buffer_destroy_internal(&exec_ctx, &buffer); + grpc_exec_ctx_finish(&exec_ctx); +} + +static void test_caching_byte_stream_reset(void) { + gpr_log(GPR_DEBUG, "test_caching_byte_stream_reset"); + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + // Create and populate slice buffer byte stream. + grpc_slice_buffer buffer; + grpc_slice_buffer_init(&buffer); + grpc_slice input[] = { + grpc_slice_from_static_string("foo"), + grpc_slice_from_static_string("bar"), + }; + for (size_t i = 0; i < GPR_ARRAY_SIZE(input); ++i) { + grpc_slice_buffer_add(&buffer, input[i]); + } + grpc_slice_buffer_stream underlying_stream; + grpc_slice_buffer_stream_init(&underlying_stream, &buffer, 0); + // Create cache and caching stream. + grpc_byte_stream_cache cache; + grpc_byte_stream_cache_init(&cache, &underlying_stream.base); + grpc_caching_byte_stream stream; + grpc_caching_byte_stream_init(&stream, &cache); + grpc_closure closure; + GRPC_CLOSURE_INIT(&closure, not_called_closure, NULL, + grpc_schedule_on_exec_ctx); + // Read one slice. + GPR_ASSERT( + grpc_byte_stream_next(&exec_ctx, &stream.base, ~(size_t)0, &closure)); + grpc_slice output; + grpc_error *error = grpc_byte_stream_pull(&exec_ctx, &stream.base, &output); + GPR_ASSERT(error == GRPC_ERROR_NONE); + GPR_ASSERT(grpc_slice_eq(input[0], output)); + grpc_slice_unref_internal(&exec_ctx, output); + // Reset the caching stream. The reads should start over from the + // first slice. + grpc_caching_byte_stream_reset(&stream); + for (size_t i = 0; i < GPR_ARRAY_SIZE(input); ++i) { + GPR_ASSERT( + grpc_byte_stream_next(&exec_ctx, &stream.base, ~(size_t)0, &closure)); + error = grpc_byte_stream_pull(&exec_ctx, &stream.base, &output); + GPR_ASSERT(error == GRPC_ERROR_NONE); + GPR_ASSERT(grpc_slice_eq(input[i], output)); + grpc_slice_unref_internal(&exec_ctx, output); + } + // Clean up. + grpc_byte_stream_destroy(&exec_ctx, &stream.base); + grpc_byte_stream_cache_destroy(&exec_ctx, &cache); + grpc_slice_buffer_destroy_internal(&exec_ctx, &buffer); + grpc_exec_ctx_finish(&exec_ctx); +} + +static void test_caching_byte_stream_shared_cache(void) { + gpr_log(GPR_DEBUG, "test_caching_byte_stream_shared_cache"); + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + // Create and populate slice buffer byte stream. + grpc_slice_buffer buffer; + grpc_slice_buffer_init(&buffer); + grpc_slice input[] = { + grpc_slice_from_static_string("foo"), + grpc_slice_from_static_string("bar"), + }; + for (size_t i = 0; i < GPR_ARRAY_SIZE(input); ++i) { + grpc_slice_buffer_add(&buffer, input[i]); + } + grpc_slice_buffer_stream underlying_stream; + grpc_slice_buffer_stream_init(&underlying_stream, &buffer, 0); + // Create cache and two caching streams. + grpc_byte_stream_cache cache; + grpc_byte_stream_cache_init(&cache, &underlying_stream.base); + grpc_caching_byte_stream stream1; + grpc_caching_byte_stream_init(&stream1, &cache); + grpc_caching_byte_stream stream2; + grpc_caching_byte_stream_init(&stream2, &cache); + grpc_closure closure; + GRPC_CLOSURE_INIT(&closure, not_called_closure, NULL, + grpc_schedule_on_exec_ctx); + // Read one slice from stream1. + GPR_ASSERT( + grpc_byte_stream_next(&exec_ctx, &stream1.base, ~(size_t)0, &closure)); + grpc_slice output; + grpc_error *error = grpc_byte_stream_pull(&exec_ctx, &stream1.base, &output); + GPR_ASSERT(error == GRPC_ERROR_NONE); + GPR_ASSERT(grpc_slice_eq(input[0], output)); + grpc_slice_unref_internal(&exec_ctx, output); + // Read all slices from stream2. + for (size_t i = 0; i < GPR_ARRAY_SIZE(input); ++i) { + GPR_ASSERT( + grpc_byte_stream_next(&exec_ctx, &stream2.base, ~(size_t)0, &closure)); + error = grpc_byte_stream_pull(&exec_ctx, &stream2.base, &output); + GPR_ASSERT(error == GRPC_ERROR_NONE); + GPR_ASSERT(grpc_slice_eq(input[i], output)); + grpc_slice_unref_internal(&exec_ctx, output); + } + // Now read the second slice from stream1. + GPR_ASSERT( + grpc_byte_stream_next(&exec_ctx, &stream1.base, ~(size_t)0, &closure)); + error = grpc_byte_stream_pull(&exec_ctx, &stream1.base, &output); + GPR_ASSERT(error == GRPC_ERROR_NONE); + GPR_ASSERT(grpc_slice_eq(input[1], output)); + grpc_slice_unref_internal(&exec_ctx, output); + // Clean up. + grpc_byte_stream_destroy(&exec_ctx, &stream1.base); + grpc_byte_stream_destroy(&exec_ctx, &stream2.base); + grpc_byte_stream_cache_destroy(&exec_ctx, &cache); + grpc_slice_buffer_destroy_internal(&exec_ctx, &buffer); + grpc_exec_ctx_finish(&exec_ctx); +} + +int main(int argc, char **argv) { + grpc_test_init(argc, argv); + test_slice_buffer_stream_basic(); + test_slice_buffer_stream_shutdown(); + test_caching_byte_stream_basic(); + test_caching_byte_stream_reset(); + test_caching_byte_stream_shared_cache(); + return 0; +} diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json index 24e7ff2b7bc..aa76fc047fb 100644 --- a/tools/run_tests/generated/sources_and_headers.json +++ b/tools/run_tests/generated/sources_and_headers.json @@ -164,6 +164,23 @@ "third_party": false, "type": "target" }, + { + "deps": [ + "gpr", + "gpr_test_util", + "grpc", + "grpc_test_util" + ], + "headers": [], + "is_filegroup": false, + "language": "c", + "name": "byte_stream_test", + "src": [ + "test/core/transport/byte_stream_test.c" + ], + "third_party": false, + "type": "target" + }, { "deps": [ "gpr", diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json index ebf30717d4e..83781f941e7 100644 --- a/tools/run_tests/generated/tests.json +++ b/tools/run_tests/generated/tests.json @@ -201,6 +201,28 @@ "windows" ] }, + { + "args": [], + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "gtest": false, + "language": "c", + "name": "byte_stream_test", + "platforms": [ + "linux", + "mac", + "posix", + "windows" + ] + }, { "args": [], "ci_platforms": [ diff --git a/vsprojects/buildtests_c.sln b/vsprojects/buildtests_c.sln index 55de734b427..6f13039cac1 100644 --- a/vsprojects/buildtests_c.sln +++ b/vsprojects/buildtests_c.sln @@ -118,6 +118,17 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bin_encoder_test", "vcxproj {29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9} EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "byte_stream_test", "vcxproj\test\byte_stream_test\byte_stream_test.vcxproj", "{9AEDA345-E3E8-BFE9-11BF-64949EF41C9C}" + ProjectSection(myProperties) = preProject + lib = "False" + EndProjectSection + ProjectSection(ProjectDependencies) = postProject + {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} = {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} + {29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9} + {EAB0A629-17A9-44DB-B5FF-E91A721FE037} = {EAB0A629-17A9-44DB-B5FF-E91A721FE037} + {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} + EndProjectSection +EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "census_context_test", "vcxproj\test\census_context_test\census_context_test.vcxproj", "{5C1CFC2D-AF3C-D7CB-BA74-D267E91CBC73}" ProjectSection(myProperties) = preProject lib = "False" @@ -1940,6 +1951,22 @@ Global {D5C70922-D68E-0E9D-9988-995E0F9A79AE}.Release-DLL|Win32.Build.0 = Release|Win32 {D5C70922-D68E-0E9D-9988-995E0F9A79AE}.Release-DLL|x64.ActiveCfg = Release|x64 {D5C70922-D68E-0E9D-9988-995E0F9A79AE}.Release-DLL|x64.Build.0 = Release|x64 + {9AEDA345-E3E8-BFE9-11BF-64949EF41C9C}.Debug|Win32.ActiveCfg = Debug|Win32 + {9AEDA345-E3E8-BFE9-11BF-64949EF41C9C}.Debug|x64.ActiveCfg = Debug|x64 + {9AEDA345-E3E8-BFE9-11BF-64949EF41C9C}.Release|Win32.ActiveCfg = Release|Win32 + {9AEDA345-E3E8-BFE9-11BF-64949EF41C9C}.Release|x64.ActiveCfg = Release|x64 + {9AEDA345-E3E8-BFE9-11BF-64949EF41C9C}.Debug|Win32.Build.0 = Debug|Win32 + {9AEDA345-E3E8-BFE9-11BF-64949EF41C9C}.Debug|x64.Build.0 = Debug|x64 + {9AEDA345-E3E8-BFE9-11BF-64949EF41C9C}.Release|Win32.Build.0 = Release|Win32 + {9AEDA345-E3E8-BFE9-11BF-64949EF41C9C}.Release|x64.Build.0 = Release|x64 + {9AEDA345-E3E8-BFE9-11BF-64949EF41C9C}.Debug-DLL|Win32.ActiveCfg = Debug|Win32 + {9AEDA345-E3E8-BFE9-11BF-64949EF41C9C}.Debug-DLL|Win32.Build.0 = Debug|Win32 + {9AEDA345-E3E8-BFE9-11BF-64949EF41C9C}.Debug-DLL|x64.ActiveCfg = Debug|x64 + {9AEDA345-E3E8-BFE9-11BF-64949EF41C9C}.Debug-DLL|x64.Build.0 = Debug|x64 + {9AEDA345-E3E8-BFE9-11BF-64949EF41C9C}.Release-DLL|Win32.ActiveCfg = Release|Win32 + {9AEDA345-E3E8-BFE9-11BF-64949EF41C9C}.Release-DLL|Win32.Build.0 = Release|Win32 + {9AEDA345-E3E8-BFE9-11BF-64949EF41C9C}.Release-DLL|x64.ActiveCfg = Release|x64 + {9AEDA345-E3E8-BFE9-11BF-64949EF41C9C}.Release-DLL|x64.Build.0 = Release|x64 {5C1CFC2D-AF3C-D7CB-BA74-D267E91CBC73}.Debug|Win32.ActiveCfg = Debug|Win32 {5C1CFC2D-AF3C-D7CB-BA74-D267E91CBC73}.Debug|x64.ActiveCfg = Debug|x64 {5C1CFC2D-AF3C-D7CB-BA74-D267E91CBC73}.Release|Win32.ActiveCfg = Release|Win32 diff --git a/vsprojects/vcxproj/test/byte_stream_test/byte_stream_test.vcxproj b/vsprojects/vcxproj/test/byte_stream_test/byte_stream_test.vcxproj new file mode 100644 index 00000000000..5d656471b1a --- /dev/null +++ b/vsprojects/vcxproj/test/byte_stream_test/byte_stream_test.vcxproj @@ -0,0 +1,199 @@ + + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {9AEDA345-E3E8-BFE9-11BF-64949EF41C9C} + true + $(SolutionDir)IntDir\$(MSBuildProjectName)\ + + + + v100 + + + v110 + + + v120 + + + v140 + + + Application + true + Unicode + + + Application + false + true + Unicode + + + + + + + + + + + + + + byte_stream_test + static + Debug + static + Debug + + + byte_stream_test + static + Release + static + Release + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + MultiThreadedDebug + true + None + false + + + Console + true + false + + + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + MultiThreadedDebug + true + None + false + + + Console + true + false + + + + + + NotUsing + Level3 + MaxSpeed + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + true + true + MultiThreaded + true + None + false + + + Console + true + false + true + true + + + + + + NotUsing + Level3 + MaxSpeed + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + true + true + MultiThreaded + true + None + false + + + Console + true + false + true + true + + + + + + + + + + {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} + + + {29D16885-7228-4C31-81ED-5F9187C7F2A9} + + + {EAB0A629-17A9-44DB-B5FF-E91A721FE037} + + + {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} + + + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + diff --git a/vsprojects/vcxproj/test/byte_stream_test/byte_stream_test.vcxproj.filters b/vsprojects/vcxproj/test/byte_stream_test/byte_stream_test.vcxproj.filters new file mode 100644 index 00000000000..65e35b7429b --- /dev/null +++ b/vsprojects/vcxproj/test/byte_stream_test/byte_stream_test.vcxproj.filters @@ -0,0 +1,21 @@ + + + + + test\core\transport + + + + + + {f172d292-4ad6-342a-f27a-096c06d43a31} + + + {d7f690de-dfe0-56fc-ff3b-38eec3931699} + + + {f78f56ef-47df-c99d-18f0-86277f7013f3} + + + + From 9701a4d4b2bc12ebd887f8291ed6fbbba0cec3c9 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Thu, 27 Jul 2017 12:19:57 +0200 Subject: [PATCH 115/127] kokoro config cleanup --- .../grpc_basictests_c_cpp_dbg.cfg | 30 +++++++++++++++++++ .../grpc_basictests_c_cpp_opt.cfg | 30 +++++++++++++++++++ .../grpc_basictests_multilang.cfg} | 4 +-- tools/internal_ci/windows/grpc_basictests.cfg | 2 +- .../internal_ci/windows/grpc_portability.cfg | 30 +++++++++++++++++++ .../grpc_basictests.cfg} | 0 .../windows/pull_request/grpc_portability.cfg | 30 +++++++++++++++++++ 7 files changed, 123 insertions(+), 3 deletions(-) create mode 100644 tools/internal_ci/linux/pull_request/grpc_basictests_c_cpp_dbg.cfg create mode 100644 tools/internal_ci/linux/pull_request/grpc_basictests_c_cpp_opt.cfg rename tools/internal_ci/{macos/grpc_master.cfg => linux/pull_request/grpc_basictests_multilang.cfg} (86%) create mode 100644 tools/internal_ci/windows/grpc_portability.cfg rename tools/internal_ci/windows/{grpc_master.cfg => pull_request/grpc_basictests.cfg} (100%) create mode 100644 tools/internal_ci/windows/pull_request/grpc_portability.cfg diff --git a/tools/internal_ci/linux/pull_request/grpc_basictests_c_cpp_dbg.cfg b/tools/internal_ci/linux/pull_request/grpc_basictests_c_cpp_dbg.cfg new file mode 100644 index 00000000000..dcc6265b34c --- /dev/null +++ b/tools/internal_ci/linux/pull_request/grpc_basictests_c_cpp_dbg.cfg @@ -0,0 +1,30 @@ +# Copyright 2017 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for the internal CI (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc/tools/internal_ci/linux/grpc_run_tests_matrix.sh" +timeout_mins: 240 +action { + define_artifacts { + regex: "**/*sponge_log.xml" + regex: "github/grpc/reports/**" + } +} + +env_vars { + key: "RUN_TESTS_FLAGS" + value: "-f basictests linux corelang dbg --inner_jobs 16 -j 1 --internal_ci" +} diff --git a/tools/internal_ci/linux/pull_request/grpc_basictests_c_cpp_opt.cfg b/tools/internal_ci/linux/pull_request/grpc_basictests_c_cpp_opt.cfg new file mode 100644 index 00000000000..f60beaf15c1 --- /dev/null +++ b/tools/internal_ci/linux/pull_request/grpc_basictests_c_cpp_opt.cfg @@ -0,0 +1,30 @@ +# Copyright 2017 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for the internal CI (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc/tools/internal_ci/linux/grpc_run_tests_matrix.sh" +timeout_mins: 240 +action { + define_artifacts { + regex: "**/*sponge_log.xml" + regex: "github/grpc/reports/**" + } +} + +env_vars { + key: "RUN_TESTS_FLAGS" + value: "-f basictests linux corelang opt --inner_jobs 16 -j 1 --internal_ci" +} diff --git a/tools/internal_ci/macos/grpc_master.cfg b/tools/internal_ci/linux/pull_request/grpc_basictests_multilang.cfg similarity index 86% rename from tools/internal_ci/macos/grpc_master.cfg rename to tools/internal_ci/linux/pull_request/grpc_basictests_multilang.cfg index ce3609c9ec4..7c16cf6a10a 100644 --- a/tools/internal_ci/macos/grpc_master.cfg +++ b/tools/internal_ci/linux/pull_request/grpc_basictests_multilang.cfg @@ -15,7 +15,7 @@ # Config file for the internal CI (in protobuf text format) # Location of the continuous shell script in repository. -build_file: "grpc/tools/internal_ci/macos/grpc_run_tests_matrix.sh" +build_file: "grpc/tools/internal_ci/linux/grpc_run_tests_matrix.sh" timeout_mins: 240 action { define_artifacts { @@ -26,5 +26,5 @@ action { env_vars { key: "RUN_TESTS_FLAGS" - value: "-f basictests macos --internal_ci -j 2 --inner_jobs 4" + value: "-f basictests linux multilang --inner_jobs 16 -j 2 --internal_ci" } diff --git a/tools/internal_ci/windows/grpc_basictests.cfg b/tools/internal_ci/windows/grpc_basictests.cfg index a116738651f..396d29ef093 100644 --- a/tools/internal_ci/windows/grpc_basictests.cfg +++ b/tools/internal_ci/windows/grpc_basictests.cfg @@ -26,5 +26,5 @@ action { env_vars { key: "RUN_TESTS_FLAGS" - value: "-f basictests windows -j 1 --inner_jobs 8 --internal_ci" + value: "-f basictests windows -j 1 --inner_jobs 8 --internal_ci --bq_result_table aggregate_results" } diff --git a/tools/internal_ci/windows/grpc_portability.cfg b/tools/internal_ci/windows/grpc_portability.cfg new file mode 100644 index 00000000000..c395cb4a949 --- /dev/null +++ b/tools/internal_ci/windows/grpc_portability.cfg @@ -0,0 +1,30 @@ +# Copyright 2017 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for the internal CI (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc/tools/internal_ci/windows/grpc_run_tests_matrix.bat" +timeout_mins: 360 +action { + define_artifacts { + regex: "**/*sponge_log.xml" + regex: "github/grpc/reports/**" + } +} + +env_vars { + key: "RUN_TESTS_FLAGS" + value: "-f portability windows -j 1 --inner_jobs 8 --internal_ci" +} diff --git a/tools/internal_ci/windows/grpc_master.cfg b/tools/internal_ci/windows/pull_request/grpc_basictests.cfg similarity index 100% rename from tools/internal_ci/windows/grpc_master.cfg rename to tools/internal_ci/windows/pull_request/grpc_basictests.cfg diff --git a/tools/internal_ci/windows/pull_request/grpc_portability.cfg b/tools/internal_ci/windows/pull_request/grpc_portability.cfg new file mode 100644 index 00000000000..c395cb4a949 --- /dev/null +++ b/tools/internal_ci/windows/pull_request/grpc_portability.cfg @@ -0,0 +1,30 @@ +# Copyright 2017 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for the internal CI (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc/tools/internal_ci/windows/grpc_run_tests_matrix.bat" +timeout_mins: 360 +action { + define_artifacts { + regex: "**/*sponge_log.xml" + regex: "github/grpc/reports/**" + } +} + +env_vars { + key: "RUN_TESTS_FLAGS" + value: "-f portability windows -j 1 --inner_jobs 8 --internal_ci" +} From db8063b1330864f187e5a0bb4fda7620c085b9dd Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Thu, 27 Jul 2017 12:59:37 +0200 Subject: [PATCH 116/127] install google-api-python-client to kokoro windows workers --- tools/internal_ci/helper_scripts/prepare_build_windows.bat | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/internal_ci/helper_scripts/prepare_build_windows.bat b/tools/internal_ci/helper_scripts/prepare_build_windows.bat index 1634acd389d..643eb380e87 100644 --- a/tools/internal_ci/helper_scripts/prepare_build_windows.bat +++ b/tools/internal_ci/helper_scripts/prepare_build_windows.bat @@ -18,4 +18,7 @@ set PATH=C:\tools\msys64\usr\bin;C:\Python27;%PATH% bash tools/internal_ci/helper_scripts/gen_report_index.sh +@rem Needed for big_query_utils +python -m pip install google-api-python-client + git submodule update --init From fa60ec70e39402df7d7b57132e99f4ade734067f Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Thu, 27 Jul 2017 17:01:31 +0200 Subject: [PATCH 117/127] Remove "--bq_result_table aggregate_results" from windows basictests. --- tools/internal_ci/windows/grpc_basictests.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/internal_ci/windows/grpc_basictests.cfg b/tools/internal_ci/windows/grpc_basictests.cfg index 396d29ef093..a116738651f 100644 --- a/tools/internal_ci/windows/grpc_basictests.cfg +++ b/tools/internal_ci/windows/grpc_basictests.cfg @@ -26,5 +26,5 @@ action { env_vars { key: "RUN_TESTS_FLAGS" - value: "-f basictests windows -j 1 --inner_jobs 8 --internal_ci --bq_result_table aggregate_results" + value: "-f basictests windows -j 1 --inner_jobs 8 --internal_ci" } From e7751807e29f7cddcdf510530ef029c04a305790 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Thu, 27 Jul 2017 12:31:45 -0700 Subject: [PATCH 118/127] Use new protocol for reporting dropped calls to grpclb balancer. --- .../grpclb/client_load_reporting_filter.c | 1 - .../client_channel/lb_policy/grpclb/grpclb.c | 26 ++---- .../lb_policy/grpclb/grpclb_client_stats.c | 79 +++++++++++----- .../lb_policy/grpclb/grpclb_client_stats.h | 27 ++++-- .../lb_policy/grpclb/load_balancer_api.c | 44 +++++++-- .../lb_policy/grpclb/load_balancer_api.h | 2 +- .../proto/grpc/lb/v1/load_balancer.pb.c | 22 +++-- .../proto/grpc/lb/v1/load_balancer.pb.h | 48 +++++----- src/proto/grpc/lb/v1/load_balancer.proto | 42 +++++---- test/cpp/end2end/grpclb_end2end_test.cc | 92 +++++++++---------- test/cpp/grpclb/grpclb_api_test.cc | 16 ++-- 11 files changed, 241 insertions(+), 158 deletions(-) diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.c b/src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.c index 52c6e38c871..568bb2ba8d7 100644 --- a/src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.c +++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.c @@ -88,7 +88,6 @@ static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, // Record call finished, optionally setting client_failed_to_send and // received. grpc_grpclb_client_stats_add_call_finished( - false /* drop_for_rate_limiting */, false /* drop_for_load_balancing */, !calld->send_initial_metadata_succeeded /* client_failed_to_send */, calld->recv_initial_metadata_succeeded /* known_received */, calld->client_stats); diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c index ebce801b37c..f248a873ba9 100644 --- a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c +++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c @@ -416,9 +416,7 @@ struct rr_connectivity_data { static bool is_server_valid(const grpc_grpclb_server *server, size_t idx, bool log) { - if (server->drop_for_rate_limiting || server->drop_for_load_balancing) { - return false; - } + if (server->drop) return false; const grpc_grpclb_ip_address *ip = &server->ip_address; if (server->port >> 16 != 0) { if (log) { @@ -462,7 +460,7 @@ static const grpc_lb_user_data_vtable lb_token_vtable = { static void parse_server(const grpc_grpclb_server *server, grpc_resolved_address *addr) { memset(addr, 0, sizeof(*addr)); - if (server->drop_for_rate_limiting || server->drop_for_load_balancing) return; + if (server->drop) return; const uint16_t netorder_port = htons((uint16_t)server->port); /* the addresses are given in binary format (a in(6)_addr struct) in * server->ip_address.bytes. */ @@ -610,7 +608,7 @@ static bool pick_from_internal_rr_locked( if (glb_policy->serverlist_index == glb_policy->serverlist->num_servers) { glb_policy->serverlist_index = 0; // Wrap-around. } - if (server->drop_for_rate_limiting || server->drop_for_load_balancing) { + if (server->drop) { // Not using the RR policy, so unref it. if (GRPC_TRACER_ON(grpc_lb_glb_trace)) { gpr_log(GPR_INFO, "Unreffing RR for drop (0x%" PRIxPTR ")", @@ -622,11 +620,8 @@ static bool pick_from_internal_rr_locked( // the client_load_reporting filter, because we do not create a // subchannel call (and therefore no client_load_reporting filter) // for dropped calls. - grpc_grpclb_client_stats_add_call_started(wc_arg->client_stats); - grpc_grpclb_client_stats_add_call_finished( - server->drop_for_rate_limiting, server->drop_for_load_balancing, - false /* failed_to_send */, false /* known_received */, - wc_arg->client_stats); + grpc_grpclb_client_stats_add_call_dropped_locked(server->load_balance_token, + wc_arg->client_stats); grpc_grpclb_client_stats_unref(wc_arg->client_stats); if (force_async) { GPR_ASSERT(wc_arg->wrapped_closure != NULL); @@ -1309,15 +1304,14 @@ static void do_send_client_load_report_locked(grpc_exec_ctx *exec_ctx, } static bool load_report_counters_are_zero(grpc_grpclb_request *request) { + grpc_grpclb_dropped_call_counts *drop_entries = + request->client_stats.calls_finished_with_drop.arg; return request->client_stats.num_calls_started == 0 && request->client_stats.num_calls_finished == 0 && - request->client_stats.num_calls_finished_with_drop_for_rate_limiting == - 0 && - request->client_stats - .num_calls_finished_with_drop_for_load_balancing == 0 && request->client_stats.num_calls_finished_with_client_failed_to_send == 0 && - request->client_stats.num_calls_finished_known_received == 0; + request->client_stats.num_calls_finished_known_received == 0 && + (drop_entries == NULL || drop_entries->num_entries == 0); } static void send_client_load_report_locked(grpc_exec_ctx *exec_ctx, void *arg, @@ -1332,7 +1326,7 @@ static void send_client_load_report_locked(grpc_exec_ctx *exec_ctx, void *arg, // Construct message payload. GPR_ASSERT(glb_policy->client_load_report_payload == NULL); grpc_grpclb_request *request = - grpc_grpclb_load_report_request_create(glb_policy->client_stats); + grpc_grpclb_load_report_request_create_locked(glb_policy->client_stats); // Skip client load report if the counters were all zero in the last // report and they are still zero in this one. if (load_report_counters_are_zero(request)) { diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.c b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.c index c762443b7c6..5b626231453 100644 --- a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.c +++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.c @@ -18,8 +18,11 @@ #include "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h" +#include + #include #include +#include #include #include @@ -29,10 +32,11 @@ struct grpc_grpclb_client_stats { gpr_refcount refs; + // This field must only be accessed via *_locked() methods. + grpc_grpclb_dropped_call_counts* drop_token_counts; + // These fields may be accessed from multiple threads at a time. gpr_atm num_calls_started; gpr_atm num_calls_finished; - gpr_atm num_calls_finished_with_drop_for_rate_limiting; - gpr_atm num_calls_finished_with_drop_for_load_balancing; gpr_atm num_calls_finished_with_client_failed_to_send; gpr_atm num_calls_finished_known_received; }; @@ -51,6 +55,7 @@ grpc_grpclb_client_stats* grpc_grpclb_client_stats_ref( void grpc_grpclb_client_stats_unref(grpc_grpclb_client_stats* client_stats) { if (gpr_unref(&client_stats->refs)) { + grpc_grpclb_dropped_call_counts_destroy(client_stats->drop_token_counts); gpr_free(client_stats); } } @@ -61,21 +66,9 @@ void grpc_grpclb_client_stats_add_call_started( } void grpc_grpclb_client_stats_add_call_finished( - bool finished_with_drop_for_rate_limiting, - bool finished_with_drop_for_load_balancing, bool finished_with_client_failed_to_send, bool finished_known_received, grpc_grpclb_client_stats* client_stats) { gpr_atm_full_fetch_add(&client_stats->num_calls_finished, (gpr_atm)1); - if (finished_with_drop_for_rate_limiting) { - gpr_atm_full_fetch_add( - &client_stats->num_calls_finished_with_drop_for_rate_limiting, - (gpr_atm)1); - } - if (finished_with_drop_for_load_balancing) { - gpr_atm_full_fetch_add( - &client_stats->num_calls_finished_with_drop_for_load_balancing, - (gpr_atm)1); - } if (finished_with_client_failed_to_send) { gpr_atm_full_fetch_add( &client_stats->num_calls_finished_with_client_failed_to_send, @@ -87,32 +80,70 @@ void grpc_grpclb_client_stats_add_call_finished( } } +void grpc_grpclb_client_stats_add_call_dropped_locked( + char* token, grpc_grpclb_client_stats* client_stats) { + // Increment num_calls_started and num_calls_finished. + gpr_atm_full_fetch_add(&client_stats->num_calls_started, (gpr_atm)1); + gpr_atm_full_fetch_add(&client_stats->num_calls_finished, (gpr_atm)1); + // Record the drop. + if (client_stats->drop_token_counts == NULL) { + client_stats->drop_token_counts = + gpr_zalloc(sizeof(grpc_grpclb_dropped_call_counts)); + } + grpc_grpclb_dropped_call_counts* drop_token_counts = + client_stats->drop_token_counts; + for (size_t i = 0; i < drop_token_counts->num_entries; ++i) { + if (strcmp(drop_token_counts->token_counts[i].token, token) == 0) { + ++drop_token_counts->token_counts[i].count; + return; + } + } + // Not found, so add a new entry. We double the size of the array each time. + size_t new_num_entries = 2; + while (new_num_entries < drop_token_counts->num_entries + 1) { + new_num_entries *= 2; + } + drop_token_counts->token_counts = + gpr_realloc(drop_token_counts->token_counts, + new_num_entries * sizeof(grpc_grpclb_drop_token_count)); + grpc_grpclb_drop_token_count* new_entry = + &drop_token_counts->token_counts[drop_token_counts->num_entries++]; + new_entry->token = gpr_strdup(token); + new_entry->count = 1; +} + static void atomic_get_and_reset_counter(int64_t* value, gpr_atm* counter) { *value = (int64_t)gpr_atm_acq_load(counter); gpr_atm_full_fetch_add(counter, (gpr_atm)(-*value)); } -void grpc_grpclb_client_stats_get( +void grpc_grpclb_client_stats_get_locked( grpc_grpclb_client_stats* client_stats, int64_t* num_calls_started, int64_t* num_calls_finished, - int64_t* num_calls_finished_with_drop_for_rate_limiting, - int64_t* num_calls_finished_with_drop_for_load_balancing, int64_t* num_calls_finished_with_client_failed_to_send, - int64_t* num_calls_finished_known_received) { + int64_t* num_calls_finished_known_received, + grpc_grpclb_dropped_call_counts** drop_token_counts) { atomic_get_and_reset_counter(num_calls_started, &client_stats->num_calls_started); atomic_get_and_reset_counter(num_calls_finished, &client_stats->num_calls_finished); - atomic_get_and_reset_counter( - num_calls_finished_with_drop_for_rate_limiting, - &client_stats->num_calls_finished_with_drop_for_rate_limiting); - atomic_get_and_reset_counter( - num_calls_finished_with_drop_for_load_balancing, - &client_stats->num_calls_finished_with_drop_for_load_balancing); atomic_get_and_reset_counter( num_calls_finished_with_client_failed_to_send, &client_stats->num_calls_finished_with_client_failed_to_send); atomic_get_and_reset_counter( num_calls_finished_known_received, &client_stats->num_calls_finished_known_received); + *drop_token_counts = client_stats->drop_token_counts; + client_stats->drop_token_counts = NULL; +} + +void grpc_grpclb_dropped_call_counts_destroy( + grpc_grpclb_dropped_call_counts* drop_entries) { + if (drop_entries != NULL) { + for (size_t i = 0; i < drop_entries->num_entries; ++i) { + gpr_free(drop_entries->token_counts[i].token); + } + gpr_free(drop_entries->token_counts); + gpr_free(drop_entries); + } } diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h index 4bb47d5c5ca..c51e2a431af 100644 --- a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h +++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h @@ -25,6 +25,16 @@ typedef struct grpc_grpclb_client_stats grpc_grpclb_client_stats; +typedef struct { + char* token; + int64_t count; +} grpc_grpclb_drop_token_count; + +typedef struct { + grpc_grpclb_drop_token_count* token_counts; + size_t num_entries; +} grpc_grpclb_dropped_call_counts; + grpc_grpclb_client_stats* grpc_grpclb_client_stats_create(); grpc_grpclb_client_stats* grpc_grpclb_client_stats_ref( grpc_grpclb_client_stats* client_stats); @@ -33,18 +43,23 @@ void grpc_grpclb_client_stats_unref(grpc_grpclb_client_stats* client_stats); void grpc_grpclb_client_stats_add_call_started( grpc_grpclb_client_stats* client_stats); void grpc_grpclb_client_stats_add_call_finished( - bool finished_with_drop_for_rate_limiting, - bool finished_with_drop_for_load_balancing, bool finished_with_client_failed_to_send, bool finished_known_received, grpc_grpclb_client_stats* client_stats); -void grpc_grpclb_client_stats_get( +// This method is not thread-safe; caller must synchronize. +void grpc_grpclb_client_stats_add_call_dropped_locked( + char* token, grpc_grpclb_client_stats* client_stats); + +// This method is not thread-safe; caller must synchronize. +void grpc_grpclb_client_stats_get_locked( grpc_grpclb_client_stats* client_stats, int64_t* num_calls_started, int64_t* num_calls_finished, - int64_t* num_calls_finished_with_drop_for_rate_limiting, - int64_t* num_calls_finished_with_drop_for_load_balancing, int64_t* num_calls_finished_with_client_failed_to_send, - int64_t* num_calls_finished_known_received); + int64_t* num_calls_finished_known_received, + grpc_grpclb_dropped_call_counts** drop_token_counts); + +void grpc_grpclb_dropped_call_counts_destroy( + grpc_grpclb_dropped_call_counts* drop_entries); #endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_GRPCLB_GRPCLB_CLIENT_STATS_H \ */ diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.c b/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.c index bec7c97a787..6fa29f326e9 100644 --- a/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.c +++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.c @@ -76,7 +76,33 @@ static void populate_timestamp(gpr_timespec timestamp, timestamp_pb->nanos = timestamp.tv_nsec; } -grpc_grpclb_request *grpc_grpclb_load_report_request_create( +static bool encode_string(pb_ostream_t *stream, const pb_field_t *field, + void *const *arg) { + char *str = *arg; + if (!pb_encode_tag_for_field(stream, field)) return false; + return pb_encode_string(stream, (uint8_t *)str, strlen(str)); +} + +static bool encode_drops(pb_ostream_t *stream, const pb_field_t *field, + void *const *arg) { + grpc_grpclb_dropped_call_counts *drop_entries = *arg; + if (drop_entries == NULL) return true; + for (size_t i = 0; i < drop_entries->num_entries; ++i) { + if (!pb_encode_tag_for_field(stream, field)) return false; + grpc_lb_v1_ClientStatsPerToken drop_message; + drop_message.load_balance_token.funcs.encode = encode_string; + drop_message.load_balance_token.arg = drop_entries->token_counts[i].token; + drop_message.has_num_calls = true; + drop_message.num_calls = drop_entries->token_counts[i].count; + if (!pb_encode_submessage(stream, grpc_lb_v1_ClientStatsPerToken_fields, + &drop_message)) { + return false; + } + } + return true; +} + +grpc_grpclb_request *grpc_grpclb_load_report_request_create_locked( grpc_grpclb_client_stats *client_stats) { grpc_grpclb_request *req = gpr_zalloc(sizeof(grpc_grpclb_request)); req->has_client_stats = true; @@ -84,18 +110,17 @@ grpc_grpclb_request *grpc_grpclb_load_report_request_create( populate_timestamp(gpr_now(GPR_CLOCK_REALTIME), &req->client_stats.timestamp); req->client_stats.has_num_calls_started = true; req->client_stats.has_num_calls_finished = true; - req->client_stats.has_num_calls_finished_with_drop_for_rate_limiting = true; - req->client_stats.has_num_calls_finished_with_drop_for_load_balancing = true; req->client_stats.has_num_calls_finished_with_client_failed_to_send = true; req->client_stats.has_num_calls_finished_with_client_failed_to_send = true; req->client_stats.has_num_calls_finished_known_received = true; - grpc_grpclb_client_stats_get( + req->client_stats.calls_finished_with_drop.funcs.encode = encode_drops; + grpc_grpclb_client_stats_get_locked( client_stats, &req->client_stats.num_calls_started, &req->client_stats.num_calls_finished, - &req->client_stats.num_calls_finished_with_drop_for_rate_limiting, - &req->client_stats.num_calls_finished_with_drop_for_load_balancing, &req->client_stats.num_calls_finished_with_client_failed_to_send, - &req->client_stats.num_calls_finished_known_received); + &req->client_stats.num_calls_finished_known_received, + (grpc_grpclb_dropped_call_counts **)&req->client_stats + .calls_finished_with_drop.arg); return req; } @@ -117,6 +142,11 @@ grpc_slice grpc_grpclb_request_encode(const grpc_grpclb_request *request) { } void grpc_grpclb_request_destroy(grpc_grpclb_request *request) { + if (request->has_client_stats) { + grpc_grpclb_dropped_call_counts *drop_entries = + request->client_stats.calls_finished_with_drop.arg; + grpc_grpclb_dropped_call_counts_destroy(drop_entries); + } gpr_free(request); } diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h b/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h index ef8d563edcd..c4a98492c9b 100644 --- a/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h +++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h @@ -44,7 +44,7 @@ typedef struct { /** Create a request for a gRPC LB service under \a lb_service_name */ grpc_grpclb_request *grpc_grpclb_request_create(const char *lb_service_name); -grpc_grpclb_request *grpc_grpclb_load_report_request_create( +grpc_grpclb_request *grpc_grpclb_load_report_request_create_locked( grpc_grpclb_client_stats *client_stats); /** Protocol Buffers v3-encode \a request */ diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c b/src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c index fb119c7fc88..6a5d54c82a0 100644 --- a/src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c +++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c @@ -33,14 +33,19 @@ const pb_field_t grpc_lb_v1_InitialLoadBalanceRequest_fields[2] = { PB_LAST_FIELD }; -const pb_field_t grpc_lb_v1_ClientStats_fields[8] = { +const pb_field_t grpc_lb_v1_ClientStatsPerToken_fields[3] = { + PB_FIELD( 1, STRING , OPTIONAL, CALLBACK, FIRST, grpc_lb_v1_ClientStatsPerToken, load_balance_token, load_balance_token, 0), + PB_FIELD( 2, INT64 , OPTIONAL, STATIC , OTHER, grpc_lb_v1_ClientStatsPerToken, num_calls, load_balance_token, 0), + PB_LAST_FIELD +}; + +const pb_field_t grpc_lb_v1_ClientStats_fields[7] = { PB_FIELD( 1, MESSAGE , OPTIONAL, STATIC , FIRST, grpc_lb_v1_ClientStats, timestamp, timestamp, &grpc_lb_v1_Timestamp_fields), PB_FIELD( 2, INT64 , OPTIONAL, STATIC , OTHER, grpc_lb_v1_ClientStats, num_calls_started, timestamp, 0), PB_FIELD( 3, INT64 , OPTIONAL, STATIC , OTHER, grpc_lb_v1_ClientStats, num_calls_finished, num_calls_started, 0), - PB_FIELD( 4, INT64 , OPTIONAL, STATIC , OTHER, grpc_lb_v1_ClientStats, num_calls_finished_with_drop_for_rate_limiting, num_calls_finished, 0), - PB_FIELD( 5, INT64 , OPTIONAL, STATIC , OTHER, grpc_lb_v1_ClientStats, num_calls_finished_with_drop_for_load_balancing, num_calls_finished_with_drop_for_rate_limiting, 0), - PB_FIELD( 6, INT64 , OPTIONAL, STATIC , OTHER, grpc_lb_v1_ClientStats, num_calls_finished_with_client_failed_to_send, num_calls_finished_with_drop_for_load_balancing, 0), + PB_FIELD( 6, INT64 , OPTIONAL, STATIC , OTHER, grpc_lb_v1_ClientStats, num_calls_finished_with_client_failed_to_send, num_calls_finished, 0), PB_FIELD( 7, INT64 , OPTIONAL, STATIC , OTHER, grpc_lb_v1_ClientStats, num_calls_finished_known_received, num_calls_finished_with_client_failed_to_send, 0), + PB_FIELD( 8, MESSAGE , REPEATED, CALLBACK, OTHER, grpc_lb_v1_ClientStats, calls_finished_with_drop, num_calls_finished_known_received, &grpc_lb_v1_ClientStatsPerToken_fields), PB_LAST_FIELD }; @@ -62,12 +67,11 @@ const pb_field_t grpc_lb_v1_ServerList_fields[3] = { PB_LAST_FIELD }; -const pb_field_t grpc_lb_v1_Server_fields[6] = { +const pb_field_t grpc_lb_v1_Server_fields[5] = { PB_FIELD( 1, BYTES , OPTIONAL, STATIC , FIRST, grpc_lb_v1_Server, ip_address, ip_address, 0), PB_FIELD( 2, INT32 , OPTIONAL, STATIC , OTHER, grpc_lb_v1_Server, port, ip_address, 0), PB_FIELD( 3, STRING , OPTIONAL, STATIC , OTHER, grpc_lb_v1_Server, load_balance_token, port, 0), - PB_FIELD( 4, BOOL , OPTIONAL, STATIC , OTHER, grpc_lb_v1_Server, drop_for_rate_limiting, load_balance_token, 0), - PB_FIELD( 5, BOOL , OPTIONAL, STATIC , OTHER, grpc_lb_v1_Server, drop_for_load_balancing, drop_for_rate_limiting, 0), + PB_FIELD( 4, BOOL , OPTIONAL, STATIC , OTHER, grpc_lb_v1_Server, drop, load_balance_token, 0), PB_LAST_FIELD }; @@ -81,7 +85,7 @@ const pb_field_t grpc_lb_v1_Server_fields[6] = { * numbers or field sizes that are larger than what can fit in 8 or 16 bit * field descriptors. */ -PB_STATIC_ASSERT((pb_membersize(grpc_lb_v1_LoadBalanceRequest, initial_request) < 65536 && pb_membersize(grpc_lb_v1_LoadBalanceRequest, client_stats) < 65536 && pb_membersize(grpc_lb_v1_ClientStats, timestamp) < 65536 && pb_membersize(grpc_lb_v1_LoadBalanceResponse, initial_response) < 65536 && pb_membersize(grpc_lb_v1_LoadBalanceResponse, server_list) < 65536 && pb_membersize(grpc_lb_v1_InitialLoadBalanceResponse, client_stats_report_interval) < 65536 && pb_membersize(grpc_lb_v1_ServerList, servers) < 65536 && pb_membersize(grpc_lb_v1_ServerList, expiration_interval) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_grpc_lb_v1_Duration_grpc_lb_v1_Timestamp_grpc_lb_v1_LoadBalanceRequest_grpc_lb_v1_InitialLoadBalanceRequest_grpc_lb_v1_ClientStats_grpc_lb_v1_LoadBalanceResponse_grpc_lb_v1_InitialLoadBalanceResponse_grpc_lb_v1_ServerList_grpc_lb_v1_Server) +PB_STATIC_ASSERT((pb_membersize(grpc_lb_v1_LoadBalanceRequest, initial_request) < 65536 && pb_membersize(grpc_lb_v1_LoadBalanceRequest, client_stats) < 65536 && pb_membersize(grpc_lb_v1_ClientStats, timestamp) < 65536 && pb_membersize(grpc_lb_v1_ClientStats, calls_finished_with_drop) < 65536 && pb_membersize(grpc_lb_v1_LoadBalanceResponse, initial_response) < 65536 && pb_membersize(grpc_lb_v1_LoadBalanceResponse, server_list) < 65536 && pb_membersize(grpc_lb_v1_InitialLoadBalanceResponse, client_stats_report_interval) < 65536 && pb_membersize(grpc_lb_v1_ServerList, servers) < 65536 && pb_membersize(grpc_lb_v1_ServerList, expiration_interval) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_grpc_lb_v1_Duration_grpc_lb_v1_Timestamp_grpc_lb_v1_LoadBalanceRequest_grpc_lb_v1_InitialLoadBalanceRequest_grpc_lb_v1_ClientStatsPerToken_grpc_lb_v1_ClientStats_grpc_lb_v1_LoadBalanceResponse_grpc_lb_v1_InitialLoadBalanceResponse_grpc_lb_v1_ServerList_grpc_lb_v1_Server) #endif #if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) @@ -92,7 +96,7 @@ PB_STATIC_ASSERT((pb_membersize(grpc_lb_v1_LoadBalanceRequest, initial_request) * numbers or field sizes that are larger than what can fit in the default * 8 bit descriptors. */ -PB_STATIC_ASSERT((pb_membersize(grpc_lb_v1_LoadBalanceRequest, initial_request) < 256 && pb_membersize(grpc_lb_v1_LoadBalanceRequest, client_stats) < 256 && pb_membersize(grpc_lb_v1_ClientStats, timestamp) < 256 && pb_membersize(grpc_lb_v1_LoadBalanceResponse, initial_response) < 256 && pb_membersize(grpc_lb_v1_LoadBalanceResponse, server_list) < 256 && pb_membersize(grpc_lb_v1_InitialLoadBalanceResponse, client_stats_report_interval) < 256 && pb_membersize(grpc_lb_v1_ServerList, servers) < 256 && pb_membersize(grpc_lb_v1_ServerList, expiration_interval) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_grpc_lb_v1_Duration_grpc_lb_v1_Timestamp_grpc_lb_v1_LoadBalanceRequest_grpc_lb_v1_InitialLoadBalanceRequest_grpc_lb_v1_ClientStats_grpc_lb_v1_LoadBalanceResponse_grpc_lb_v1_InitialLoadBalanceResponse_grpc_lb_v1_ServerList_grpc_lb_v1_Server) +PB_STATIC_ASSERT((pb_membersize(grpc_lb_v1_LoadBalanceRequest, initial_request) < 256 && pb_membersize(grpc_lb_v1_LoadBalanceRequest, client_stats) < 256 && pb_membersize(grpc_lb_v1_ClientStats, timestamp) < 256 && pb_membersize(grpc_lb_v1_ClientStats, calls_finished_with_drop) < 256 && pb_membersize(grpc_lb_v1_LoadBalanceResponse, initial_response) < 256 && pb_membersize(grpc_lb_v1_LoadBalanceResponse, server_list) < 256 && pb_membersize(grpc_lb_v1_InitialLoadBalanceResponse, client_stats_report_interval) < 256 && pb_membersize(grpc_lb_v1_ServerList, servers) < 256 && pb_membersize(grpc_lb_v1_ServerList, expiration_interval) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_grpc_lb_v1_Duration_grpc_lb_v1_Timestamp_grpc_lb_v1_LoadBalanceRequest_grpc_lb_v1_InitialLoadBalanceRequest_grpc_lb_v1_ClientStatsPerToken_grpc_lb_v1_ClientStats_grpc_lb_v1_LoadBalanceResponse_grpc_lb_v1_InitialLoadBalanceResponse_grpc_lb_v1_ServerList_grpc_lb_v1_Server) #endif diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h b/src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h index d3ae919ec27..93333d1aed2 100644 --- a/src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h +++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h @@ -14,6 +14,13 @@ extern "C" { #endif /* Struct definitions */ +typedef struct _grpc_lb_v1_ClientStatsPerToken { + pb_callback_t load_balance_token; + bool has_num_calls; + int64_t num_calls; +/* @@protoc_insertion_point(struct:grpc_lb_v1_ClientStatsPerToken) */ +} grpc_lb_v1_ClientStatsPerToken; + typedef struct _grpc_lb_v1_Duration { bool has_seconds; int64_t seconds; @@ -36,10 +43,8 @@ typedef struct _grpc_lb_v1_Server { int32_t port; bool has_load_balance_token; char load_balance_token[50]; - bool has_drop_for_rate_limiting; - bool drop_for_rate_limiting; - bool has_drop_for_load_balancing; - bool drop_for_load_balancing; + bool has_drop; + bool drop; /* @@protoc_insertion_point(struct:grpc_lb_v1_Server) */ } grpc_lb_v1_Server; @@ -58,14 +63,11 @@ typedef struct _grpc_lb_v1_ClientStats { int64_t num_calls_started; bool has_num_calls_finished; int64_t num_calls_finished; - bool has_num_calls_finished_with_drop_for_rate_limiting; - int64_t num_calls_finished_with_drop_for_rate_limiting; - bool has_num_calls_finished_with_drop_for_load_balancing; - int64_t num_calls_finished_with_drop_for_load_balancing; bool has_num_calls_finished_with_client_failed_to_send; int64_t num_calls_finished_with_client_failed_to_send; bool has_num_calls_finished_known_received; int64_t num_calls_finished_known_received; + pb_callback_t calls_finished_with_drop; /* @@protoc_insertion_point(struct:grpc_lb_v1_ClientStats) */ } grpc_lb_v1_ClientStats; @@ -107,39 +109,41 @@ typedef struct _grpc_lb_v1_LoadBalanceResponse { #define grpc_lb_v1_Timestamp_init_default {false, 0, false, 0} #define grpc_lb_v1_LoadBalanceRequest_init_default {false, grpc_lb_v1_InitialLoadBalanceRequest_init_default, false, grpc_lb_v1_ClientStats_init_default} #define grpc_lb_v1_InitialLoadBalanceRequest_init_default {false, ""} -#define grpc_lb_v1_ClientStats_init_default {false, grpc_lb_v1_Timestamp_init_default, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} +#define grpc_lb_v1_ClientStatsPerToken_init_default {{{NULL}, NULL}, false, 0} +#define grpc_lb_v1_ClientStats_init_default {false, grpc_lb_v1_Timestamp_init_default, false, 0, false, 0, false, 0, false, 0, {{NULL}, NULL}} #define grpc_lb_v1_LoadBalanceResponse_init_default {false, grpc_lb_v1_InitialLoadBalanceResponse_init_default, false, grpc_lb_v1_ServerList_init_default} #define grpc_lb_v1_InitialLoadBalanceResponse_init_default {false, "", false, grpc_lb_v1_Duration_init_default} #define grpc_lb_v1_ServerList_init_default {{{NULL}, NULL}, false, grpc_lb_v1_Duration_init_default} -#define grpc_lb_v1_Server_init_default {false, {0, {0}}, false, 0, false, "", false, 0, false, 0} +#define grpc_lb_v1_Server_init_default {false, {0, {0}}, false, 0, false, "", false, 0} #define grpc_lb_v1_Duration_init_zero {false, 0, false, 0} #define grpc_lb_v1_Timestamp_init_zero {false, 0, false, 0} #define grpc_lb_v1_LoadBalanceRequest_init_zero {false, grpc_lb_v1_InitialLoadBalanceRequest_init_zero, false, grpc_lb_v1_ClientStats_init_zero} #define grpc_lb_v1_InitialLoadBalanceRequest_init_zero {false, ""} -#define grpc_lb_v1_ClientStats_init_zero {false, grpc_lb_v1_Timestamp_init_zero, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} +#define grpc_lb_v1_ClientStatsPerToken_init_zero {{{NULL}, NULL}, false, 0} +#define grpc_lb_v1_ClientStats_init_zero {false, grpc_lb_v1_Timestamp_init_zero, false, 0, false, 0, false, 0, false, 0, {{NULL}, NULL}} #define grpc_lb_v1_LoadBalanceResponse_init_zero {false, grpc_lb_v1_InitialLoadBalanceResponse_init_zero, false, grpc_lb_v1_ServerList_init_zero} #define grpc_lb_v1_InitialLoadBalanceResponse_init_zero {false, "", false, grpc_lb_v1_Duration_init_zero} #define grpc_lb_v1_ServerList_init_zero {{{NULL}, NULL}, false, grpc_lb_v1_Duration_init_zero} -#define grpc_lb_v1_Server_init_zero {false, {0, {0}}, false, 0, false, "", false, 0, false, 0} +#define grpc_lb_v1_Server_init_zero {false, {0, {0}}, false, 0, false, "", false, 0} /* Field tags (for use in manual encoding/decoding) */ +#define grpc_lb_v1_ClientStatsPerToken_load_balance_token_tag 1 +#define grpc_lb_v1_ClientStatsPerToken_num_calls_tag 2 #define grpc_lb_v1_Duration_seconds_tag 1 #define grpc_lb_v1_Duration_nanos_tag 2 #define grpc_lb_v1_InitialLoadBalanceRequest_name_tag 1 #define grpc_lb_v1_Server_ip_address_tag 1 #define grpc_lb_v1_Server_port_tag 2 #define grpc_lb_v1_Server_load_balance_token_tag 3 -#define grpc_lb_v1_Server_drop_for_rate_limiting_tag 4 -#define grpc_lb_v1_Server_drop_for_load_balancing_tag 5 +#define grpc_lb_v1_Server_drop_tag 4 #define grpc_lb_v1_Timestamp_seconds_tag 1 #define grpc_lb_v1_Timestamp_nanos_tag 2 #define grpc_lb_v1_ClientStats_timestamp_tag 1 #define grpc_lb_v1_ClientStats_num_calls_started_tag 2 #define grpc_lb_v1_ClientStats_num_calls_finished_tag 3 -#define grpc_lb_v1_ClientStats_num_calls_finished_with_drop_for_rate_limiting_tag 4 -#define grpc_lb_v1_ClientStats_num_calls_finished_with_drop_for_load_balancing_tag 5 #define grpc_lb_v1_ClientStats_num_calls_finished_with_client_failed_to_send_tag 6 #define grpc_lb_v1_ClientStats_num_calls_finished_known_received_tag 7 +#define grpc_lb_v1_ClientStats_calls_finished_with_drop_tag 8 #define grpc_lb_v1_InitialLoadBalanceResponse_load_balancer_delegate_tag 1 #define grpc_lb_v1_InitialLoadBalanceResponse_client_stats_report_interval_tag 2 #define grpc_lb_v1_ServerList_servers_tag 1 @@ -154,22 +158,24 @@ extern const pb_field_t grpc_lb_v1_Duration_fields[3]; extern const pb_field_t grpc_lb_v1_Timestamp_fields[3]; extern const pb_field_t grpc_lb_v1_LoadBalanceRequest_fields[3]; extern const pb_field_t grpc_lb_v1_InitialLoadBalanceRequest_fields[2]; -extern const pb_field_t grpc_lb_v1_ClientStats_fields[8]; +extern const pb_field_t grpc_lb_v1_ClientStatsPerToken_fields[3]; +extern const pb_field_t grpc_lb_v1_ClientStats_fields[7]; extern const pb_field_t grpc_lb_v1_LoadBalanceResponse_fields[3]; extern const pb_field_t grpc_lb_v1_InitialLoadBalanceResponse_fields[3]; extern const pb_field_t grpc_lb_v1_ServerList_fields[3]; -extern const pb_field_t grpc_lb_v1_Server_fields[6]; +extern const pb_field_t grpc_lb_v1_Server_fields[5]; /* Maximum encoded size of messages (where known) */ #define grpc_lb_v1_Duration_size 22 #define grpc_lb_v1_Timestamp_size 22 -#define grpc_lb_v1_LoadBalanceRequest_size 226 +#define grpc_lb_v1_LoadBalanceRequest_size (140 + grpc_lb_v1_ClientStats_size) #define grpc_lb_v1_InitialLoadBalanceRequest_size 131 -#define grpc_lb_v1_ClientStats_size 90 +/* grpc_lb_v1_ClientStatsPerToken_size depends on runtime parameters */ +/* grpc_lb_v1_ClientStats_size depends on runtime parameters */ #define grpc_lb_v1_LoadBalanceResponse_size (98 + grpc_lb_v1_ServerList_size) #define grpc_lb_v1_InitialLoadBalanceResponse_size 90 /* grpc_lb_v1_ServerList_size depends on runtime parameters */ -#define grpc_lb_v1_Server_size 85 +#define grpc_lb_v1_Server_size 83 /* Message IDs (where set with "msgid" option) */ #ifdef PB_MSGID diff --git a/src/proto/grpc/lb/v1/load_balancer.proto b/src/proto/grpc/lb/v1/load_balancer.proto index b13b3438cf2..0a33568bd67 100644 --- a/src/proto/grpc/lb/v1/load_balancer.proto +++ b/src/proto/grpc/lb/v1/load_balancer.proto @@ -67,6 +67,15 @@ message InitialLoadBalanceRequest { string name = 1; } +// Contains the number of calls finished for a particular load balance token. +message ClientStatsPerToken { + // See Server.load_balance_token. + string load_balance_token = 1; + + // The total number of RPCs that finished associated with the token. + int64 num_calls = 2; +} + // Contains client level statistics that are useful to load balancing. Each // count except the timestamp should be reset to zero after reporting the stats. message ClientStats { @@ -79,20 +88,17 @@ message ClientStats { // The total number of RPCs that finished. int64 num_calls_finished = 3; - // The total number of RPCs that were dropped by the client because of rate - // limiting. - int64 num_calls_finished_with_drop_for_rate_limiting = 4; - - // The total number of RPCs that were dropped by the client because of load - // balancing. - int64 num_calls_finished_with_drop_for_load_balancing = 5; - // The total number of RPCs that failed to reach a server except dropped RPCs. int64 num_calls_finished_with_client_failed_to_send = 6; // The total number of RPCs that finished and are known to have been received // by a server. int64 num_calls_finished_known_received = 7; + + // The list of dropped calls. + repeated ClientStatsPerToken calls_finished_with_drop = 8; + + reserved 4, 5; } message LoadBalanceResponse { @@ -134,10 +140,8 @@ message ServerList { Duration expiration_interval = 3; } -// Contains server information. When none of the [drop_for_*] fields are true, -// use the other fields. When drop_for_rate_limiting is true, ignore all other -// fields. Use drop_for_load_balancing only when it is true and -// drop_for_rate_limiting is false. +// Contains server information. When the drop field is not true, use the other +// fields. message Server { // A resolved address for the server, serialized in network-byte-order. It may // either be an IPv4 or IPv6 address. @@ -149,16 +153,16 @@ message Server { // An opaque but printable token given to the frontend for each pick. All // frontend requests for that pick must include the token in its initial // metadata. The token is used by the backend to verify the request and to - // allow the backend to report load to the gRPC LB system. + // allow the backend to report load to the gRPC LB system. The token is also + // used in client stats for reporting dropped calls. // // Its length is variable but less than 50 bytes. string load_balance_token = 3; - // Indicates whether this particular request should be dropped by the client - // for rate limiting. - bool drop_for_rate_limiting = 4; + // Indicates whether this particular request should be dropped by the client. + // If the request is dropped, there will be a corresponding entry in + // ClientStats.calls_finished_with_drop. + bool drop = 4; - // Indicates whether this particular request should be dropped by the client - // for load balancing. - bool drop_for_load_balancing = 5; + reserved 5; } diff --git a/test/cpp/end2end/grpclb_end2end_test.cc b/test/cpp/end2end/grpclb_end2end_test.cc index 1f3255d18d8..e403ee66fc8 100644 --- a/test/cpp/end2end/grpclb_end2end_test.cc +++ b/test/cpp/end2end/grpclb_end2end_test.cc @@ -45,6 +45,7 @@ extern "C" { #include "src/proto/grpc/lb/v1/load_balancer.grpc.pb.h" #include "src/proto/grpc/testing/echo.grpc.pb.h" +#include #include // TODO(dgq): Other scenarios in need of testing: @@ -142,22 +143,20 @@ grpc::string Ip4ToPackedString(const char* ip_str) { struct ClientStats { size_t num_calls_started = 0; size_t num_calls_finished = 0; - size_t num_calls_finished_with_drop_for_rate_limiting = 0; - size_t num_calls_finished_with_drop_for_load_balancing = 0; size_t num_calls_finished_with_client_failed_to_send = 0; size_t num_calls_finished_known_received = 0; + std::map drop_token_counts; ClientStats& operator+=(const ClientStats& other) { num_calls_started += other.num_calls_started; num_calls_finished += other.num_calls_finished; - num_calls_finished_with_drop_for_rate_limiting += - other.num_calls_finished_with_drop_for_rate_limiting; - num_calls_finished_with_drop_for_load_balancing += - other.num_calls_finished_with_drop_for_load_balancing; num_calls_finished_with_client_failed_to_send += other.num_calls_finished_with_client_failed_to_send; num_calls_finished_known_received += other.num_calls_finished_known_received; + for (const auto& p : other.drop_token_counts) { + drop_token_counts[p.first] += p.second; + } return *this; } }; @@ -218,17 +217,17 @@ class BalancerServiceImpl : public BalancerService { request.client_stats().num_calls_started(); client_stats_.num_calls_finished += request.client_stats().num_calls_finished(); - client_stats_.num_calls_finished_with_drop_for_rate_limiting += - request.client_stats() - .num_calls_finished_with_drop_for_rate_limiting(); - client_stats_.num_calls_finished_with_drop_for_load_balancing += - request.client_stats() - .num_calls_finished_with_drop_for_load_balancing(); client_stats_.num_calls_finished_with_client_failed_to_send += request.client_stats() .num_calls_finished_with_client_failed_to_send(); client_stats_.num_calls_finished_known_received += request.client_stats().num_calls_finished_known_received(); + for (const auto& drop_token_count : + request.client_stats().calls_finished_with_drop()) { + client_stats_ + .drop_token_counts[drop_token_count.load_balance_token()] += + drop_token_count.num_calls(); + } load_report_cond_.notify_one(); } done: @@ -252,16 +251,15 @@ class BalancerServiceImpl : public BalancerService { } static LoadBalanceResponse BuildResponseForBackends( - const std::vector& backend_ports, int num_drops_for_rate_limiting, - int num_drops_for_load_balancing) { + const std::vector& backend_ports, + const std::map& drop_token_counts) { LoadBalanceResponse response; - for (int i = 0; i < num_drops_for_rate_limiting; ++i) { - auto* server = response.mutable_server_list()->add_servers(); - server->set_drop_for_rate_limiting(true); - } - for (int i = 0; i < num_drops_for_load_balancing; ++i) { - auto* server = response.mutable_server_list()->add_servers(); - server->set_drop_for_load_balancing(true); + for (const auto& drop_token_count : drop_token_counts) { + for (size_t i = 0; i < drop_token_count.second; ++i) { + auto* server = response.mutable_server_list()->add_servers(); + server->set_drop(true); + server->set_load_balance_token(drop_token_count.first); + } } for (const int& backend_port : backend_ports) { auto* server = response.mutable_server_list()->add_servers(); @@ -499,7 +497,7 @@ class SingleBalancerTest : public GrpclbEnd2endTest { TEST_F(SingleBalancerTest, Vanilla) { const size_t kNumRpcsPerAddress = 100; ScheduleResponseForBalancer( - 0, BalancerServiceImpl::BuildResponseForBackends(GetBackendPorts(), 0, 0), + 0, BalancerServiceImpl::BuildResponseForBackends(GetBackendPorts(), {}), 0); // Make sure that trying to connect works without a call. channel_->GetState(true /* try_to_connect */); @@ -538,7 +536,7 @@ TEST_F(SingleBalancerTest, InitiallyEmptyServerlist) { ScheduleResponseForBalancer(0, LoadBalanceResponse(), 0); // Send non-empty serverlist only after kServerlistDelayMs ScheduleResponseForBalancer( - 0, BalancerServiceImpl::BuildResponseForBackends(GetBackendPorts(), 0, 0), + 0, BalancerServiceImpl::BuildResponseForBackends(GetBackendPorts(), {}), kServerlistDelayMs); const auto t0 = system_clock::now(); @@ -580,11 +578,11 @@ TEST_F(SingleBalancerTest, RepeatedServerlist) { // Send a serverlist right away. ScheduleResponseForBalancer( - 0, BalancerServiceImpl::BuildResponseForBackends(GetBackendPorts(), 0, 0), + 0, BalancerServiceImpl::BuildResponseForBackends(GetBackendPorts(), {}), 0); // ... and the same one a bit later. ScheduleResponseForBalancer( - 0, BalancerServiceImpl::BuildResponseForBackends(GetBackendPorts(), 0, 0), + 0, BalancerServiceImpl::BuildResponseForBackends(GetBackendPorts(), {}), kServerlistDelayMs); // Send num_backends/2 requests. @@ -648,10 +646,9 @@ TEST_F(UpdatesTest, UpdateBalancers) { const std::vector first_backend{GetBackendPorts()[0]}; const std::vector second_backend{GetBackendPorts()[1]}; ScheduleResponseForBalancer( - 0, BalancerServiceImpl::BuildResponseForBackends(first_backend, 0, 0), 0); + 0, BalancerServiceImpl::BuildResponseForBackends(first_backend, {}), 0); ScheduleResponseForBalancer( - 1, BalancerServiceImpl::BuildResponseForBackends(second_backend, 0, 0), - 0); + 1, BalancerServiceImpl::BuildResponseForBackends(second_backend, {}), 0); // Start servers and send 10 RPCs per server. gpr_log(GPR_INFO, "========= BEFORE FIRST BATCH =========="); @@ -726,10 +723,9 @@ TEST_F(UpdatesTest, UpdateBalancersRepeated) { const std::vector second_backend{GetBackendPorts()[0]}; ScheduleResponseForBalancer( - 0, BalancerServiceImpl::BuildResponseForBackends(first_backend, 0, 0), 0); + 0, BalancerServiceImpl::BuildResponseForBackends(first_backend, {}), 0); ScheduleResponseForBalancer( - 1, BalancerServiceImpl::BuildResponseForBackends(second_backend, 0, 0), - 0); + 1, BalancerServiceImpl::BuildResponseForBackends(second_backend, {}), 0); // Start servers and send 10 RPCs per server. gpr_log(GPR_INFO, "========= BEFORE FIRST BATCH =========="); @@ -809,10 +805,9 @@ TEST_F(UpdatesTest, UpdateBalancersDeadUpdate) { const std::vector second_backend{GetBackendPorts()[1]}; ScheduleResponseForBalancer( - 0, BalancerServiceImpl::BuildResponseForBackends(first_backend, 0, 0), 0); + 0, BalancerServiceImpl::BuildResponseForBackends(first_backend, {}), 0); ScheduleResponseForBalancer( - 1, BalancerServiceImpl::BuildResponseForBackends(second_backend, 0, 0), - 0); + 1, BalancerServiceImpl::BuildResponseForBackends(second_backend, {}), 0); // Start servers and send 10 RPCs per server. gpr_log(GPR_INFO, "========= BEFORE FIRST BATCH =========="); @@ -901,7 +896,8 @@ TEST_F(UpdatesTest, UpdateBalancersDeadUpdate) { TEST_F(SingleBalancerTest, Drop) { const size_t kNumRpcsPerAddress = 100; ScheduleResponseForBalancer( - 0, BalancerServiceImpl::BuildResponseForBackends(GetBackendPorts(), 1, 2), + 0, BalancerServiceImpl::BuildResponseForBackends( + GetBackendPorts(), {{"rate_limiting", 1}, {"load_balancing", 2}}), 0); // Send 100 RPCs for each server and drop address. const auto& statuses_and_responses = @@ -936,7 +932,9 @@ TEST_F(SingleBalancerTest, Drop) { TEST_F(SingleBalancerTest, DropAllFirst) { // All registered addresses are marked as "drop". ScheduleResponseForBalancer( - 0, BalancerServiceImpl::BuildResponseForBackends({}, 1, 1), 0); + 0, BalancerServiceImpl::BuildResponseForBackends( + {}, {{"rate_limiting", 1}, {"load_balancing", 1}}), + 0); const auto& statuses_and_responses = SendRpc(kMessage_, 1); for (const auto& status_and_response : statuses_and_responses) { const Status& status = status_and_response.first; @@ -947,10 +945,12 @@ TEST_F(SingleBalancerTest, DropAllFirst) { TEST_F(SingleBalancerTest, DropAll) { ScheduleResponseForBalancer( - 0, BalancerServiceImpl::BuildResponseForBackends(GetBackendPorts(), 0, 0), + 0, BalancerServiceImpl::BuildResponseForBackends(GetBackendPorts(), {}), 0); ScheduleResponseForBalancer( - 0, BalancerServiceImpl::BuildResponseForBackends({}, 1, 1), 1000); + 0, BalancerServiceImpl::BuildResponseForBackends( + {}, {{"rate_limiting", 1}, {"load_balancing", 1}}), + 1000); // First call succeeds. auto statuses_and_responses = SendRpc(kMessage_, 1); @@ -980,7 +980,7 @@ class SingleBalancerWithClientLoadReportingTest : public GrpclbEnd2endTest { TEST_F(SingleBalancerWithClientLoadReportingTest, Vanilla) { const size_t kNumRpcsPerAddress = 100; ScheduleResponseForBalancer( - 0, BalancerServiceImpl::BuildResponseForBackends(GetBackendPorts(), 0, 0), + 0, BalancerServiceImpl::BuildResponseForBackends(GetBackendPorts(), {}), 0); // Send 100 RPCs per server. const auto& statuses_and_responses = @@ -1009,17 +1009,17 @@ TEST_F(SingleBalancerWithClientLoadReportingTest, Vanilla) { EXPECT_EQ(kNumRpcsPerAddress * num_backends_, client_stats.num_calls_started); EXPECT_EQ(kNumRpcsPerAddress * num_backends_, client_stats.num_calls_finished); - EXPECT_EQ(0U, client_stats.num_calls_finished_with_drop_for_rate_limiting); - EXPECT_EQ(0U, client_stats.num_calls_finished_with_drop_for_load_balancing); EXPECT_EQ(0U, client_stats.num_calls_finished_with_client_failed_to_send); EXPECT_EQ(kNumRpcsPerAddress * num_backends_, client_stats.num_calls_finished_known_received); + EXPECT_THAT(client_stats.drop_token_counts, ::testing::ElementsAre()); } TEST_F(SingleBalancerWithClientLoadReportingTest, Drop) { const size_t kNumRpcsPerAddress = 3; ScheduleResponseForBalancer( - 0, BalancerServiceImpl::BuildResponseForBackends(GetBackendPorts(), 2, 1), + 0, BalancerServiceImpl::BuildResponseForBackends( + GetBackendPorts(), {{"rate_limiting", 2}, {"load_balancing", 1}}), 0); // Send 100 RPCs for each server and drop address. const auto& statuses_and_responses = @@ -1056,13 +1056,13 @@ TEST_F(SingleBalancerWithClientLoadReportingTest, Drop) { client_stats.num_calls_started); EXPECT_EQ(kNumRpcsPerAddress * (num_backends_ + 3), client_stats.num_calls_finished); - EXPECT_EQ(kNumRpcsPerAddress * 2, - client_stats.num_calls_finished_with_drop_for_rate_limiting); - EXPECT_EQ(kNumRpcsPerAddress, - client_stats.num_calls_finished_with_drop_for_load_balancing); EXPECT_EQ(0U, client_stats.num_calls_finished_with_client_failed_to_send); EXPECT_EQ(kNumRpcsPerAddress * num_backends_, client_stats.num_calls_finished_known_received); + EXPECT_THAT(client_stats.drop_token_counts, + ::testing::ElementsAre( + ::testing::Pair("load_balancing", kNumRpcsPerAddress), + ::testing::Pair("rate_limiting", kNumRpcsPerAddress * 2))); } } // namespace diff --git a/test/cpp/grpclb/grpclb_api_test.cc b/test/cpp/grpclb/grpclb_api_test.cc index cec96665038..6b0350e1f91 100644 --- a/test/cpp/grpclb/grpclb_api_test.cc +++ b/test/cpp/grpclb/grpclb_api_test.cc @@ -91,13 +91,13 @@ TEST_F(GrpclbTest, ParseResponseServerList) { auto* server = serverlist->add_servers(); server->set_ip_address(Ip4ToPackedString("127.0.0.1")); server->set_port(12345); - server->set_drop_for_rate_limiting(true); - server->set_drop_for_load_balancing(false); + server->set_load_balance_token("rate_limting"); + server->set_drop(true); server = response.mutable_server_list()->add_servers(); server->set_ip_address(Ip4ToPackedString("10.0.0.1")); server->set_port(54321); - server->set_drop_for_rate_limiting(false); - server->set_drop_for_load_balancing(true); + server->set_load_balance_token("load_balancing"); + server->set_drop(true); auto* expiration_interval = serverlist->mutable_expiration_interval(); expiration_interval->set_seconds(888); expiration_interval->set_nanos(999); @@ -112,14 +112,14 @@ TEST_F(GrpclbTest, ParseResponseServerList) { EXPECT_EQ(PackedStringToIp(c_serverlist->servers[0]->ip_address), "127.0.0.1"); EXPECT_EQ(c_serverlist->servers[0]->port, 12345); - EXPECT_TRUE(c_serverlist->servers[0]->drop_for_rate_limiting); - EXPECT_FALSE(c_serverlist->servers[0]->drop_for_load_balancing); + EXPECT_STREQ(c_serverlist->servers[0]->load_balance_token, "rate_limting"); + EXPECT_TRUE(c_serverlist->servers[0]->drop); EXPECT_TRUE(c_serverlist->servers[1]->has_ip_address); EXPECT_EQ(PackedStringToIp(c_serverlist->servers[1]->ip_address), "10.0.0.1"); EXPECT_EQ(c_serverlist->servers[1]->port, 54321); - EXPECT_FALSE(c_serverlist->servers[1]->drop_for_rate_limiting); - EXPECT_TRUE(c_serverlist->servers[1]->drop_for_load_balancing); + EXPECT_STREQ(c_serverlist->servers[1]->load_balance_token, "load_balancing"); + EXPECT_TRUE(c_serverlist->servers[1]->drop); EXPECT_TRUE(c_serverlist->expiration_interval.has_seconds); EXPECT_EQ(c_serverlist->expiration_interval.seconds, 888); From a0bfba212236ad35ef14872a1bcb53317c91ffc8 Mon Sep 17 00:00:00 2001 From: Sree Kuchibhotla Date: Thu, 27 Jul 2017 15:24:04 -0700 Subject: [PATCH 119/127] Fix use after free error in cq --- src/core/lib/surface/completion_queue.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/core/lib/surface/completion_queue.c b/src/core/lib/surface/completion_queue.c index 978d7b41719..3851993c924 100644 --- a/src/core/lib/surface/completion_queue.c +++ b/src/core/lib/surface/completion_queue.c @@ -855,8 +855,7 @@ static grpc_event cq_next(grpc_completion_queue *cq, gpr_timespec deadline, inconsistent state. If it is the latter, we shold do a 0-timeout poll so that the thread comes back quickly from poll to make a second attempt at popping. Not doing this can potentially deadlock this - thread - forever (if the deadline is infinity) */ + thread forever (if the deadline is infinity) */ if (cq_event_queue_num_items(&cqd->queue) > 0) { iteration_deadline = gpr_time_0(GPR_CLOCK_MONOTONIC); } @@ -869,10 +868,8 @@ static grpc_event cq_next(grpc_completion_queue *cq, gpr_timespec deadline, if (cq_event_queue_num_items(&cqd->queue) > 0) { /* Go to the beginning of the loop. No point doing a poll because (cq->shutdown == true) is only possible when there is no pending - work - (i.e cq->pending_events == 0) and any outstanding - grpc_cq_completion - events are already queued on this cq */ + work (i.e cq->pending_events == 0) and any outstanding completion + events should have already been queued on this cq */ continue; } @@ -909,11 +906,6 @@ static grpc_event cq_next(grpc_completion_queue *cq, gpr_timespec deadline, is_finished_arg.first_loop = false; } - GRPC_SURFACE_TRACE_RETURNED_EVENT(cq, &ret); - GRPC_CQ_INTERNAL_UNREF(&exec_ctx, cq, "next"); - grpc_exec_ctx_finish(&exec_ctx); - GPR_ASSERT(is_finished_arg.stolen_completion == NULL); - if (cq_event_queue_num_items(&cqd->queue) > 0 && gpr_atm_no_barrier_load(&cqd->pending_events) > 0) { gpr_mu_lock(cq->mu); @@ -921,6 +913,11 @@ static grpc_event cq_next(grpc_completion_queue *cq, gpr_timespec deadline, gpr_mu_unlock(cq->mu); } + GRPC_SURFACE_TRACE_RETURNED_EVENT(cq, &ret); + GRPC_CQ_INTERNAL_UNREF(&exec_ctx, cq, "next"); + grpc_exec_ctx_finish(&exec_ctx); + GPR_ASSERT(is_finished_arg.stolen_completion == NULL); + GPR_TIMER_END("grpc_completion_queue_next", 0); return ret; From 1f92c17bed24004ea6af7e8afa018c59d9843329 Mon Sep 17 00:00:00 2001 From: Matt Kwong Date: Thu, 27 Jul 2017 17:06:12 -0700 Subject: [PATCH 120/127] Enable BQ access for Kokoro Macs --- tools/internal_ci/helper_scripts/prepare_build_macos_rc | 5 +++++ tools/internal_ci/macos/grpc_basictests.cfg | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/tools/internal_ci/helper_scripts/prepare_build_macos_rc b/tools/internal_ci/helper_scripts/prepare_build_macos_rc index 89e8e24351c..00105d48383 100644 --- a/tools/internal_ci/helper_scripts/prepare_build_macos_rc +++ b/tools/internal_ci/helper_scripts/prepare_build_macos_rc @@ -27,6 +27,11 @@ ulimit -n 10000 # show current limits ulimit -a +# Add GCP credentials for BQ access +# pip does not install google-api-python-client properly, so use easy_install +sudo easy_install --upgrade google-api-python-client +export GOOGLE_APPLICATION_CREDENTIALS=${KOKORO_GFILE_DIR}/GrpcTesting-d0eeee2db331.json +gcloud auth activate-service-account --key-file=$GOOGLE_APPLICATION_CREDENTIALS # required to build protobuf brew install gflags diff --git a/tools/internal_ci/macos/grpc_basictests.cfg b/tools/internal_ci/macos/grpc_basictests.cfg index ce3609c9ec4..e10c2e36b27 100644 --- a/tools/internal_ci/macos/grpc_basictests.cfg +++ b/tools/internal_ci/macos/grpc_basictests.cfg @@ -16,6 +16,7 @@ # Location of the continuous shell script in repository. build_file: "grpc/tools/internal_ci/macos/grpc_run_tests_matrix.sh" +gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/GrpcTesting-d0eeee2db331.json" timeout_mins: 240 action { define_artifacts { @@ -26,5 +27,5 @@ action { env_vars { key: "RUN_TESTS_FLAGS" - value: "-f basictests macos --internal_ci -j 2 --inner_jobs 4" + value: "-f basictests macos --internal_ci -j 2 --inner_jobs 4 --bq_result_table aggregate_results" } From cd22f11905dacc72f08b0255c1cf73d0cea4c7c2 Mon Sep 17 00:00:00 2001 From: Alexander Polcyn Date: Thu, 27 Jul 2017 17:54:59 -0700 Subject: [PATCH 121/127] properly finish bidi calls when there is an initial error --- src/ruby/lib/grpc/generic/active_call.rb | 15 ++++++++++++- src/ruby/spec/generic/client_stub_spec.rb | 26 +++++++++++++++++------ 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/src/ruby/lib/grpc/generic/active_call.rb b/src/ruby/lib/grpc/generic/active_call.rb index 87b29c26eae..10eb70b4a7f 100644 --- a/src/ruby/lib/grpc/generic/active_call.rb +++ b/src/ruby/lib/grpc/generic/active_call.rb @@ -480,7 +480,20 @@ module GRPC def bidi_streamer(requests, metadata: {}, &blk) raise_error_if_already_executed # Metadata might have already been sent if this is an operation view - merge_metadata_and_send_if_not_already_sent(metadata) + begin + merge_metadata_and_send_if_not_already_sent(metadata) + rescue GRPC::Core::CallError => e + batch_result = @call.run_batch(RECV_STATUS_ON_CLIENT => nil) + set_input_stream_done + set_output_stream_done + attach_status_results_and_complete_call(batch_result) + raise e + rescue => e + set_input_stream_done + set_output_stream_done + raise e + end + bd = BidiCall.new(@call, @marshal, @unmarshal, diff --git a/src/ruby/spec/generic/client_stub_spec.rb b/src/ruby/spec/generic/client_stub_spec.rb index 26cb970a1fa..1f22809ea66 100644 --- a/src/ruby/spec/generic/client_stub_spec.rb +++ b/src/ruby/spec/generic/client_stub_spec.rb @@ -590,8 +590,22 @@ describe 'ClientStub' do th.join end - # TODO: add test for metadata-related ArgumentError in a bidi call once - # issue mentioned in https://github.com/grpc/grpc/issues/10526 is fixed + it 'should raise ArgumentError if metadata contains invalid values' do + @metadata.merge!(k3: 3) + stub = GRPC::ClientStub.new(@host, :this_channel_is_insecure) + expect do + get_responses(stub).collect { |r| r } + end.to raise_error(ArgumentError, + /Header values must be of type string or array/) + end + + it 'terminates if the call fails to start' do + # don't start the server + stub = GRPC::ClientStub.new(@host, :this_channel_is_insecure) + expect do + get_responses(stub, deadline: from_relative_time(0)).collect { |r| r } + end.to raise_error(GRPC::BadStatus) + end it 'should send metadata to the server ok' do th = run_bidi_streamer_echo_ping_pong(@sent_msgs, @pass, true, @@ -604,9 +618,9 @@ describe 'ClientStub' do end describe 'without a call operation' do - def get_responses(stub) + def get_responses(stub, deadline: nil) e = stub.bidi_streamer(@method, @sent_msgs, noop, noop, - metadata: @metadata) + metadata: @metadata, deadline: deadline) expect(e).to be_a(Enumerator) e end @@ -618,10 +632,10 @@ describe 'ClientStub' do after(:each) do @op.wait # make sure wait doesn't hang end - def get_responses(stub, run_start_call_first: false) + def get_responses(stub, run_start_call_first: false, deadline: nil) @op = stub.bidi_streamer(@method, @sent_msgs, noop, noop, return_op: true, - metadata: @metadata) + metadata: @metadata, deadline: deadline) expect(@op).to be_a(GRPC::ActiveCall::Operation) @op.start_call if run_start_call_first e = @op.execute From 6a7935e14e6500d94e52b4dd5b049fa236eba7e0 Mon Sep 17 00:00:00 2001 From: David Garcia Quintas Date: Thu, 27 Jul 2017 19:24:52 -0700 Subject: [PATCH 122/127] Watch the LB channel using the right initial conn. state --- .../client_channel/lb_policy/grpclb/grpclb.c | 3 ++- test/cpp/end2end/grpclb_end2end_test.cc | 15 ++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c index f248a873ba9..3d76aaac023 100644 --- a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c +++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c @@ -1772,7 +1772,8 @@ static void glb_update_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, if (!glb_policy->watching_lb_channel) { // Watch the LB channel connectivity for connection. - glb_policy->lb_channel_connectivity = GRPC_CHANNEL_INIT; + glb_policy->lb_channel_connectivity = grpc_channel_check_connectivity_state( + glb_policy->lb_channel, true /* try to connect */); grpc_channel_element *client_channel_elem = grpc_channel_stack_last_element( grpc_channel_get_channel_stack(glb_policy->lb_channel)); GPR_ASSERT(client_channel_elem->filter == &grpc_client_channel_filter); diff --git a/test/cpp/end2end/grpclb_end2end_test.cc b/test/cpp/end2end/grpclb_end2end_test.cc index e403ee66fc8..66f47ce5898 100644 --- a/test/cpp/end2end/grpclb_end2end_test.cc +++ b/test/cpp/end2end/grpclb_end2end_test.cc @@ -172,11 +172,12 @@ class BalancerServiceImpl : public BalancerService { shutdown_(false) {} Status BalanceLoad(ServerContext* context, Stream* stream) override { - gpr_log(GPR_INFO, "LB: BalanceLoad"); + gpr_log(GPR_INFO, "LB[%p]: BalanceLoad", this); LoadBalanceRequest request; stream->Read(&request); IncreaseRequestCount(); - gpr_log(GPR_INFO, "LB: recv msg '%s'", request.DebugString().c_str()); + gpr_log(GPR_INFO, "LB[%p]: recv msg '%s'", this, + request.DebugString().c_str()); if (client_load_reporting_interval_seconds_ > 0) { LoadBalanceResponse initial_response; @@ -207,7 +208,7 @@ class BalancerServiceImpl : public BalancerService { if (client_load_reporting_interval_seconds_ > 0) { request.Clear(); stream->Read(&request); - gpr_log(GPR_INFO, "LB: recv client load report msg: '%s'", + gpr_log(GPR_INFO, "LB[%p]: recv client load report msg: '%s'", this, request.DebugString().c_str()); GPR_ASSERT(request.has_client_stats()); // We need to acquire the lock here in order to prevent the notify_one @@ -231,7 +232,7 @@ class BalancerServiceImpl : public BalancerService { load_report_cond_.notify_one(); } done: - gpr_log(GPR_INFO, "LB: done"); + gpr_log(GPR_INFO, "LB[%p]: done", this); return Status::OK; } @@ -246,7 +247,7 @@ class BalancerServiceImpl : public BalancerService { std::unique_lock lock(mu_); const bool prev = !shutdown_; shutdown_ = true; - gpr_log(GPR_INFO, "LB: shut down"); + gpr_log(GPR_INFO, "LB[%p]: shut down", this); return prev; } @@ -283,13 +284,13 @@ class BalancerServiceImpl : public BalancerService { private: void SendResponse(Stream* stream, const LoadBalanceResponse& response, int delay_ms) { - gpr_log(GPR_INFO, "LB: sleeping for %d ms...", delay_ms); + gpr_log(GPR_INFO, "LB[%p]: sleeping for %d ms...", this, delay_ms); if (delay_ms > 0) { gpr_sleep_until( gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_millis(delay_ms, GPR_TIMESPAN))); } - gpr_log(GPR_INFO, "LB: Woke up! Sending response '%s'", + gpr_log(GPR_INFO, "LB[%p]: Woke up! Sending response '%s'", this, response.DebugString().c_str()); IncreaseResponseCount(); stream->Write(response); From 0133cc6fd8c549151498291e7796b9719502c8c5 Mon Sep 17 00:00:00 2001 From: ncteisen Date: Thu, 27 Jul 2017 16:24:15 -0700 Subject: [PATCH 123/127] Avoid benchmarking allocs --- test/cpp/qps/server.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/test/cpp/qps/server.h b/test/cpp/qps/server.h index c0dac96d8b8..df27a4368ea 100644 --- a/test/cpp/qps/server.h +++ b/test/cpp/qps/server.h @@ -80,8 +80,11 @@ class Server { return false; } payload->set_type(type); - std::unique_ptr body(new char[size]()); - payload->set_body(body.get(), size); + // Don't waste time creating a new payload of identical size. + if (payload->body().length() != (size_t)size) { + std::unique_ptr body(new char[size]()); + payload->set_body(body.get(), size); + } return true; } From fc950fbeb52ca472f1bb8dab25011b1e794c8a23 Mon Sep 17 00:00:00 2001 From: David Garcia Quintas Date: Thu, 27 Jul 2017 19:41:12 -0700 Subject: [PATCH 124/127] Fix bug in handling of RR connectivity transition to SHUTDOWN --- .../client_channel/lb_policy/grpclb/grpclb.c | 49 ++++++------- .../lb_policy/round_robin/round_robin.c | 6 ++ test/cpp/end2end/grpclb_end2end_test.cc | 70 ++++++++++++++++++- 3 files changed, 98 insertions(+), 27 deletions(-) diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c index f248a873ba9..aadba3fe99d 100644 --- a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c +++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c @@ -710,7 +710,6 @@ static void create_rr_locked(grpc_exec_ctx *exec_ctx, glb_lb_policy *glb_policy, return; } glb_policy->rr_policy = new_rr_policy; - grpc_error *rr_state_error = NULL; const grpc_connectivity_state rr_state = grpc_lb_policy_check_connectivity_locked(exec_ctx, glb_policy->rr_policy, @@ -736,7 +735,7 @@ static void create_rr_locked(grpc_exec_ctx *exec_ctx, glb_lb_policy *glb_policy, rr_connectivity->state = rr_state; /* Subscribe to changes to the connectivity of the new RR */ - GRPC_LB_POLICY_WEAK_REF(&glb_policy->base, "rr_connectivity_sched"); + GRPC_LB_POLICY_WEAK_REF(&glb_policy->base, "glb_rr_connectivity_cb"); grpc_lb_policy_notify_on_state_change_locked(exec_ctx, glb_policy->rr_policy, &rr_connectivity->state, &rr_connectivity->on_change); @@ -801,32 +800,31 @@ static void glb_rr_connectivity_changed_locked(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { rr_connectivity_data *rr_connectivity = arg; glb_lb_policy *glb_policy = rr_connectivity->glb_policy; - - const bool shutting_down = glb_policy->shutting_down; - bool unref_needed = false; - GRPC_ERROR_REF(error); - - if (rr_connectivity->state == GRPC_CHANNEL_SHUTDOWN || shutting_down) { - /* RR policy shutting down. Don't renew subscription and free the arg of - * this callback. In addition we need to stash away the current policy to - * be UNREF'd after releasing the lock. Otherwise, if the UNREF is the last - * one, the policy would be destroyed, alongside the lock, which would - * result in a use-after-free */ - unref_needed = true; + if (glb_policy->shutting_down) { + GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &glb_policy->base, + "glb_rr_connectivity_cb"); gpr_free(rr_connectivity); - } else { /* rr state != SHUTDOWN && !shutting down: biz as usual */ - update_lb_connectivity_status_locked( - exec_ctx, glb_policy, rr_connectivity->state, GRPC_ERROR_REF(error)); - /* Resubscribe. Reuse the "rr_connectivity_cb" weak ref. */ - grpc_lb_policy_notify_on_state_change_locked( - exec_ctx, glb_policy->rr_policy, &rr_connectivity->state, - &rr_connectivity->on_change); + return; } - if (unref_needed) { + if (rr_connectivity->state == GRPC_CHANNEL_SHUTDOWN) { + /* An RR policy that has transitioned into the SHUTDOWN connectivity state + * should not be considered for picks or updates: the SHUTDOWN state is a + * sink, policies can't transition back from it. .*/ + GRPC_LB_POLICY_UNREF(exec_ctx, glb_policy->rr_policy, + "rr_connectivity_shutdown"); + glb_policy->rr_policy = NULL; GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &glb_policy->base, - "rr_connectivity_cb"); + "glb_rr_connectivity_cb"); + gpr_free(rr_connectivity); + return; } - GRPC_ERROR_UNREF(error); + /* rr state != SHUTDOWN && !glb_policy->shutting down: biz as usual */ + update_lb_connectivity_status_locked( + exec_ctx, glb_policy, rr_connectivity->state, GRPC_ERROR_REF(error)); + /* Resubscribe. Reuse the "glb_rr_connectivity_cb" weak ref. */ + grpc_lb_policy_notify_on_state_change_locked(exec_ctx, glb_policy->rr_policy, + &rr_connectivity->state, + &rr_connectivity->on_change); } static void destroy_balancer_name(grpc_exec_ctx *exec_ctx, @@ -990,7 +988,6 @@ static grpc_lb_policy *glb_create(grpc_exec_ctx *exec_ctx, gpr_free(glb_policy); return NULL; } - GRPC_CLOSURE_INIT(&glb_policy->lb_channel_on_connectivity_changed, glb_lb_channel_on_connectivity_changed_cb, glb_policy, grpc_combiner_scheduler(args->combiner)); @@ -1047,7 +1044,7 @@ static void glb_shutdown_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { glb_policy->pending_picks = NULL; pending_ping *pping = glb_policy->pending_pings; glb_policy->pending_pings = NULL; - if (glb_policy->rr_policy) { + if (glb_policy->rr_policy != NULL) { GRPC_LB_POLICY_UNREF(exec_ctx, glb_policy->rr_policy, "glb_shutdown"); } // We destroy the LB channel here because diff --git a/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.c b/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.c index bc40165cfb8..a7f7e9542c8 100644 --- a/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.c +++ b/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.c @@ -74,6 +74,9 @@ typedef struct round_robin_lb_policy { bool started_picking; /** are we shutting down? */ bool shutdown; + /** has the policy gotten into the GRPC_CHANNEL_SHUTDOWN? No picks can be + * service after this point, the policy will never transition out. */ + bool in_connectivity_shutdown; /** List of picks that are waiting on connectivity */ pending_pick *pending_picks; @@ -420,6 +423,8 @@ static int rr_pick_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, grpc_call_context_element *context, void **user_data, grpc_closure *on_complete) { round_robin_lb_policy *p = (round_robin_lb_policy *)pol; + GPR_ASSERT(!p->shutdown); + GPR_ASSERT(!p->in_connectivity_shutdown); if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) { gpr_log(GPR_INFO, "[RR %p] Trying to pick", (void *)pol); } @@ -532,6 +537,7 @@ static grpc_connectivity_state update_lb_connectivity_status_locked( grpc_connectivity_state_set(exec_ctx, &p->state_tracker, GRPC_CHANNEL_SHUTDOWN, GRPC_ERROR_REF(error), "rr_shutdown"); + p->in_connectivity_shutdown = true; new_state = GRPC_CHANNEL_SHUTDOWN; } else if (subchannel_list->num_transient_failures == p->subchannel_list->num_subchannels) { /* 4) TRANSIENT_FAILURE */ diff --git a/test/cpp/end2end/grpclb_end2end_test.cc b/test/cpp/end2end/grpclb_end2end_test.cc index e403ee66fc8..2f3acb6ee10 100644 --- a/test/cpp/end2end/grpclb_end2end_test.cc +++ b/test/cpp/end2end/grpclb_end2end_test.cc @@ -132,6 +132,19 @@ class BackendServiceImpl : public BackendService { IncreaseResponseCount(); return status; } + + // Returns true on its first invocation, false otherwise. + bool Shutdown() { + std::unique_lock lock(mu_); + const bool prev = !shutdown_; + shutdown_ = true; + gpr_log(GPR_INFO, "Backend: shut down"); + return prev; + } + + private: + std::mutex mu_; + bool shutdown_ = false; }; grpc::string Ip4ToPackedString(const char* ip_str) { @@ -339,7 +352,7 @@ class GrpclbEnd2endTest : public ::testing::Test { void TearDown() override { for (size_t i = 0; i < backends_.size(); ++i) { - backend_servers_[i].Shutdown(); + if (backends_[i]->Shutdown()) backend_servers_[i].Shutdown(); } for (size_t i = 0; i < balancers_.size(); ++i) { if (balancers_[i]->Shutdown()) balancer_servers_[i].Shutdown(); @@ -637,6 +650,61 @@ TEST_F(SingleBalancerTest, RepeatedServerlist) { EXPECT_EQ("grpclb", channel_->GetLoadBalancingPolicyName()); } +TEST_F(SingleBalancerTest, BackendsRestart) { + const size_t kNumRpcsPerAddress = 100; + ScheduleResponseForBalancer( + 0, BalancerServiceImpl::BuildResponseForBackends(GetBackendPorts(), {}), + 0); + // Make sure that trying to connect works without a call. + channel_->GetState(true /* try_to_connect */); + // Send 100 RPCs per server. + auto statuses_and_responses = + SendRpc(kMessage_, kNumRpcsPerAddress * num_backends_); + for (const auto& status_and_response : statuses_and_responses) { + const Status& status = status_and_response.first; + const EchoResponse& response = status_and_response.second; + EXPECT_TRUE(status.ok()) << "code=" << status.error_code() + << " message=" << status.error_message(); + EXPECT_EQ(response.message(), kMessage_); + } + // Each backend should have gotten 100 requests. + for (size_t i = 0; i < backends_.size(); ++i) { + EXPECT_EQ(kNumRpcsPerAddress, + backend_servers_[i].service_->request_count()); + } + balancers_[0]->NotifyDoneWithServerlists(); + // The balancer got a single request. + EXPECT_EQ(1U, balancer_servers_[0].service_->request_count()); + // and sent a single response. + EXPECT_EQ(1U, balancer_servers_[0].service_->response_count()); + for (size_t i = 0; i < backends_.size(); ++i) { + if (backends_[i]->Shutdown()) backend_servers_[i].Shutdown(); + } + statuses_and_responses = SendRpc(kMessage_, 1); + for (const auto& status_and_response : statuses_and_responses) { + const Status& status = status_and_response.first; + EXPECT_FALSE(status.ok()); + } + for (size_t i = 0; i < num_backends_; ++i) { + backends_.emplace_back(new BackendServiceImpl()); + backend_servers_.emplace_back(ServerThread( + "backend", server_host_, backends_.back().get())); + } + // The following RPC will fail due to the backend ports having changed. It + // will nonetheless exercise the grpclb-roundrobin handling of the RR policy + // having gone into shutdown. + // TODO(dgq): implement the "backend restart" component as well. We need extra + // machinery to either update the LB responses "on the fly" or instruct + // backends which ports to restart on. + statuses_and_responses = SendRpc(kMessage_, 1); + for (const auto& status_and_response : statuses_and_responses) { + const Status& status = status_and_response.first; + EXPECT_FALSE(status.ok()); + } + // Check LB policy name for the channel. + EXPECT_EQ("grpclb", channel_->GetLoadBalancingPolicyName()); +} + class UpdatesTest : public GrpclbEnd2endTest { public: UpdatesTest() : GrpclbEnd2endTest(4, 3, 0) {} From f0cf6e2b6c394150d250eaf698989e6692da45b2 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Thu, 27 Jul 2017 13:32:56 +0200 Subject: [PATCH 125/127] fix fetching of GCE default credentials on kokoro windows --- .../internal_ci/helper_scripts/prepare_build_windows.bat | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tools/internal_ci/helper_scripts/prepare_build_windows.bat b/tools/internal_ci/helper_scripts/prepare_build_windows.bat index 643eb380e87..95fd6a3e8e3 100644 --- a/tools/internal_ci/helper_scripts/prepare_build_windows.bat +++ b/tools/internal_ci/helper_scripts/prepare_build_windows.bat @@ -18,6 +18,14 @@ set PATH=C:\tools\msys64\usr\bin;C:\Python27;%PATH% bash tools/internal_ci/helper_scripts/gen_report_index.sh +@rem Add GCE DNS server and disable IPv6 to: +@rem 1. allow resolving metadata.google.internal hostname +@rem 2. make fetching default GCE credential by oauth2client work +netsh interface ipv4 add dnsservers "Local Area Connection 8" 10.240.0.1 index=1 +netsh interface teredo set state disabled +netsh interface 6to4 set state disabled +netsh interface isatap set state disabled + @rem Needed for big_query_utils python -m pip install google-api-python-client From a8381dee2c45e51a5a1f295a77cdfaafea80ec69 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Thu, 27 Jul 2017 17:37:46 +0200 Subject: [PATCH 126/127] add back --bq_result_table aggregate_results --- tools/internal_ci/windows/grpc_basictests.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/internal_ci/windows/grpc_basictests.cfg b/tools/internal_ci/windows/grpc_basictests.cfg index a116738651f..396d29ef093 100644 --- a/tools/internal_ci/windows/grpc_basictests.cfg +++ b/tools/internal_ci/windows/grpc_basictests.cfg @@ -26,5 +26,5 @@ action { env_vars { key: "RUN_TESTS_FLAGS" - value: "-f basictests windows -j 1 --inner_jobs 8 --internal_ci" + value: "-f basictests windows -j 1 --inner_jobs 8 --internal_ci --bq_result_table aggregate_results" } From b74b94cdac6139120aa708f704f67f8fdc705a31 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Fri, 28 Jul 2017 09:47:32 +0200 Subject: [PATCH 127/127] better way to enable fetching GCE default credentials --- .../internal_ci/helper_scripts/prepare_build_windows.bat | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tools/internal_ci/helper_scripts/prepare_build_windows.bat b/tools/internal_ci/helper_scripts/prepare_build_windows.bat index 95fd6a3e8e3..69e087e1db1 100644 --- a/tools/internal_ci/helper_scripts/prepare_build_windows.bat +++ b/tools/internal_ci/helper_scripts/prepare_build_windows.bat @@ -18,13 +18,12 @@ set PATH=C:\tools\msys64\usr\bin;C:\Python27;%PATH% bash tools/internal_ci/helper_scripts/gen_report_index.sh -@rem Add GCE DNS server and disable IPv6 to: +@rem Update DNS settings to: @rem 1. allow resolving metadata.google.internal hostname @rem 2. make fetching default GCE credential by oauth2client work -netsh interface ipv4 add dnsservers "Local Area Connection 8" 10.240.0.1 index=1 -netsh interface teredo set state disabled -netsh interface 6to4 set state disabled -netsh interface isatap set state disabled +netsh interface ip set dns "Local Area Connection 8" static 169.254.169.254 primary +netsh interface ip add dnsservers "Local Area Connection 8" 8.8.8.8 index=2 +netsh interface ip add dnsservers "Local Area Connection 8" 8.8.4.4 index=3 @rem Needed for big_query_utils python -m pip install google-api-python-client