From 9fe284e5e431487cafa73c71503f1ed4b9beb332 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Mon, 12 Sep 2016 11:22:27 -0700 Subject: [PATCH 01/48] Add map of path name to grpc_method_config data structures. --- src/core/ext/client_config/client_channel.c | 59 +++++-- src/core/ext/client_config/resolver_result.c | 159 +++++++++++++++++++ src/core/ext/client_config/resolver_result.h | 40 +++++ 3 files changed, 246 insertions(+), 12 deletions(-) diff --git a/src/core/ext/client_config/client_channel.c b/src/core/ext/client_config/client_channel.c index 2e6f253d386..c50585d1544 100644 --- a/src/core/ext/client_config/client_channel.c +++ b/src/core/ext/client_config/client_channel.c @@ -52,6 +52,9 @@ #include "src/core/lib/support/string.h" #include "src/core/lib/surface/channel.h" #include "src/core/lib/transport/connectivity_state.h" +#include "src/core/lib/transport/metadata.h" +#include "src/core/lib/transport/metadata_batch.h" +#include "src/core/lib/transport/static_metadata.h" /* Client channel implementation */ @@ -73,7 +76,9 @@ typedef struct client_channel_channel_data { /** currently active load balancer - guarded by mu */ grpc_lb_policy *lb_policy; /** incoming resolver result - set by resolver.next(), guarded by mu */ - grpc_resolver_result *resolver_result; + grpc_resolver_result *incoming_resolver_result; + /** current resolver result */ + grpc_resolver_result *current_resolver_result; /** a list of closures that are all waiting for config to come in */ grpc_closure_list waiting_for_config_closures; /** resolver callback */ @@ -175,14 +180,15 @@ static void on_resolver_result_changed(grpc_exec_ctx *exec_ctx, void *arg, bool exit_idle = false; grpc_error *state_error = GRPC_ERROR_CREATE("No load balancing policy"); - if (chand->resolver_result != NULL) { + if (chand->incoming_resolver_result != NULL) { grpc_lb_policy_args lb_policy_args; lb_policy_args.addresses = - grpc_resolver_result_get_addresses(chand->resolver_result); + grpc_resolver_result_get_addresses(chand->incoming_resolver_result); lb_policy_args.client_channel_factory = chand->client_channel_factory; lb_policy = grpc_lb_policy_create( exec_ctx, - grpc_resolver_result_get_lb_policy_name(chand->resolver_result), + grpc_resolver_result_get_lb_policy_name( + chand->incoming_resolver_result), &lb_policy_args); if (lb_policy != NULL) { GRPC_LB_POLICY_REF(lb_policy, "config_change"); @@ -190,8 +196,11 @@ static void on_resolver_result_changed(grpc_exec_ctx *exec_ctx, void *arg, state = grpc_lb_policy_check_connectivity(exec_ctx, lb_policy, &state_error); } - grpc_resolver_result_unref(exec_ctx, chand->resolver_result); - chand->resolver_result = NULL; + if (chand->current_resolver_result != NULL) { + grpc_resolver_result_unref(exec_ctx, chand->current_resolver_result); + } + chand->current_resolver_result = chand->incoming_resolver_result; + chand->incoming_resolver_result = NULL; } if (lb_policy != NULL) { @@ -225,7 +234,8 @@ static void on_resolver_result_changed(grpc_exec_ctx *exec_ctx, void *arg, watch_lb_policy(exec_ctx, chand, lb_policy, state); } GRPC_CHANNEL_STACK_REF(chand->owning_stack, "resolver"); - grpc_resolver_next(exec_ctx, chand->resolver, &chand->resolver_result, + grpc_resolver_next(exec_ctx, chand->resolver, + &chand->incoming_resolver_result, &chand->on_resolver_result_changed); gpr_mu_unlock(&chand->mu); } else { @@ -362,6 +372,9 @@ static void cc_destroy_channel_elem(grpc_exec_ctx *exec_ctx, chand->interested_parties); GRPC_LB_POLICY_UNREF(exec_ctx, chand->lb_policy, "channel"); } + if (chand->current_resolver_result != NULL) { + grpc_resolver_result_unref(exec_ctx, chand->current_resolver_result); + } grpc_connectivity_state_destroy(exec_ctx, &chand->state_tracker); grpc_pollset_set_destroy(chand->interested_parties); gpr_mu_destroy(&chand->mu); @@ -397,6 +410,9 @@ typedef struct client_channel_call_data { grpc_connected_subchannel *connected_subchannel; grpc_polling_entity *pollent; + grpc_mdstr *path; + grpc_method_config *method_config; + grpc_transport_stream_op *waiting_ops; size_t waiting_ops_count; size_t waiting_ops_capacity; @@ -466,7 +482,9 @@ static void retry_waiting_locked(grpc_exec_ctx *exec_ctx, call_data *calld) { static void subchannel_ready(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { - call_data *calld = arg; + grpc_call_element *elem = arg; + call_data *calld = elem->call_data; + channel_data *chand = elem->channel_data; gpr_mu_lock(&calld->mu); GPR_ASSERT(calld->creation_phase == GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL); @@ -481,6 +499,11 @@ static void subchannel_ready(grpc_exec_ctx *exec_ctx, void *arg, GRPC_ERROR_CREATE_REFERENCING( "Cancelled before creating subchannel", &error, 1)); } else { + /* Get method config. */ +// FIXME: need to actually use the config data! + calld->method_config = grpc_resolver_result_get_method_config( + chand->current_resolver_result, calld->path); + /* Create call on subchannel. */ grpc_subchannel_call *subchannel_call = NULL; grpc_error *new_error = grpc_connected_subchannel_create_call( exec_ctx, calld->connected_subchannel, calld->pollent, @@ -586,7 +609,8 @@ static bool pick_subchannel(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, if (chand->resolver != NULL && !chand->started_resolving) { chand->started_resolving = true; GRPC_CHANNEL_STACK_REF(chand->owning_stack, "resolver"); - grpc_resolver_next(exec_ctx, chand->resolver, &chand->resolver_result, + grpc_resolver_next(exec_ctx, chand->resolver, + &chand->incoming_resolver_result, &chand->on_resolver_result_changed); } if (chand->resolver != NULL) { @@ -677,8 +701,15 @@ retry: if (calld->creation_phase == GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING && calld->connected_subchannel == NULL && op->send_initial_metadata != NULL) { + for (grpc_linked_mdelem *mdelem = op->send_initial_metadata->list.head; + mdelem != NULL; mdelem = mdelem->next) { + if (mdelem->md->key == GRPC_MDSTR_PATH) { + calld->path = GRPC_MDSTR_REF(mdelem->md->value); + break; + } + } calld->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL; - grpc_closure_init(&calld->next_step, subchannel_ready, calld); + grpc_closure_init(&calld->next_step, subchannel_ready, elem); GRPC_CALL_STACK_REF(calld->owning_call, "pick_subchannel"); if (pick_subchannel(exec_ctx, elem, op->send_initial_metadata, op->send_initial_metadata_flags, @@ -718,6 +749,8 @@ static grpc_error *cc_init_call_elem(grpc_exec_ctx *exec_ctx, gpr_atm_rel_store(&calld->subchannel_call, 0); gpr_mu_init(&calld->mu); calld->connected_subchannel = NULL; + calld->path = NULL; + calld->method_config = NULL; calld->waiting_ops = NULL; calld->waiting_ops_count = 0; calld->waiting_ops_capacity = 0; @@ -733,6 +766,7 @@ static void cc_destroy_call_elem(grpc_exec_ctx *exec_ctx, const grpc_call_final_info *final_info, void *and_free_memory) { call_data *calld = elem->call_data; + if (calld->path != NULL) GRPC_MDSTR_UNREF(calld->path); grpc_subchannel_call *call = GET_CALL(calld); if (call != NULL && call != CANCELLED_CALL) { GRPC_SUBCHANNEL_CALL_UNREF(exec_ctx, call, "client_channel_destroy_call"); @@ -784,7 +818,7 @@ void grpc_client_channel_set_resolver_and_client_channel_factory( chand->exit_idle_when_lb_policy_arrives) { chand->started_resolving = true; GRPC_CHANNEL_STACK_REF(chand->owning_stack, "resolver"); - grpc_resolver_next(exec_ctx, resolver, &chand->resolver_result, + grpc_resolver_next(exec_ctx, resolver, &chand->incoming_resolver_result, &chand->on_resolver_result_changed); } chand->client_channel_factory = client_channel_factory; @@ -806,7 +840,8 @@ grpc_connectivity_state grpc_client_channel_check_connectivity_state( if (!chand->started_resolving && chand->resolver != NULL) { GRPC_CHANNEL_STACK_REF(chand->owning_stack, "resolver"); chand->started_resolving = true; - grpc_resolver_next(exec_ctx, chand->resolver, &chand->resolver_result, + grpc_resolver_next(exec_ctx, chand->resolver, + &chand->incoming_resolver_result, &chand->on_resolver_result_changed); } } diff --git a/src/core/ext/client_config/resolver_result.c b/src/core/ext/client_config/resolver_result.c index b0602d583d6..235ea5b23f3 100644 --- a/src/core/ext/client_config/resolver_result.c +++ b/src/core/ext/client_config/resolver_result.c @@ -38,6 +38,11 @@ #include #include +#include "src/core/lib/support/murmur_hash.h" +#include "src/core/lib/transport/metadata.h" + +/* grpc_addresses */ + grpc_addresses *grpc_addresses_create(size_t num_addresses) { grpc_addresses *addresses = gpr_malloc(sizeof(grpc_addresses)); addresses->num_addresses = num_addresses; @@ -69,10 +74,148 @@ void grpc_addresses_destroy(grpc_addresses *addresses) { gpr_free(addresses); } +/* grpc_method_config */ + +struct grpc_method_config { + gpr_refcount refs; + bool* wait_for_ready; + gpr_timespec* timeout; + int32_t* max_request_message_bytes; + int32_t* max_response_message_bytes; +}; + +grpc_method_config *grpc_method_config_create( + bool *wait_for_ready, gpr_timespec *timeout, + int32_t *max_request_message_bytes, int32_t *max_response_message_bytes) { + grpc_method_config *config = gpr_malloc(sizeof(*config)); + memset(config, 0, sizeof(*config)); + gpr_ref_init(&config->refs, 1); + if (wait_for_ready != NULL) { + config->wait_for_ready = gpr_malloc(sizeof(*wait_for_ready)); + *config->wait_for_ready = *wait_for_ready; + } + if (timeout != NULL) { + config->timeout = gpr_malloc(sizeof(*timeout)); + *config->timeout = *timeout; + } + if (max_request_message_bytes != NULL) { + config->max_request_message_bytes = + gpr_malloc(sizeof(*max_request_message_bytes)); + *config->max_request_message_bytes = *max_request_message_bytes; + } + if (max_response_message_bytes != NULL) { + config->max_response_message_bytes = + gpr_malloc(sizeof(*max_response_message_bytes)); + *config->max_response_message_bytes = *max_response_message_bytes; + } + return config; +} + +grpc_method_config *grpc_method_config_ref(grpc_method_config *method_config) { + gpr_ref(&method_config->refs); + return method_config; +} + +void grpc_method_config_unref(grpc_method_config *method_config) { + if (gpr_unref(&method_config->refs)) { + gpr_free(method_config->wait_for_ready); + gpr_free(method_config->timeout); + gpr_free(method_config->max_request_message_bytes); + gpr_free(method_config->max_response_message_bytes); + gpr_free(method_config); + } +} + +bool* grpc_method_config_get_wait_for_ready( + grpc_method_config *method_config) { + return method_config->wait_for_ready; +} + +gpr_timespec* grpc_method_config_get_timeout( + grpc_method_config *method_config) { + return method_config->timeout; +} + +int32_t* grpc_method_config_get_max_request_message_bytes( + grpc_method_config *method_config) { + return method_config->max_request_message_bytes; +} + +int32_t* grpc_method_config_get_max_response_message_bytes( + grpc_method_config *method_config) { + return method_config->max_response_message_bytes; +} + +/* method_config_table */ + +typedef struct method_config_table_entry { + grpc_mdstr *path; + grpc_method_config *method_config; + struct method_config_table_entry *next; // Chaining for collisions. +} method_config_table_entry; + +#define METHOD_CONFIG_TABLE_SIZE 30 +typedef struct method_config_table { + method_config_table_entry *entries[METHOD_CONFIG_TABLE_SIZE]; + uint32_t hash_seed; +} method_config_table; + +static void method_config_table_init(method_config_table* table) { + memset(table, 0, sizeof(*table)); + table->hash_seed = (uint32_t)gpr_now(GPR_CLOCK_REALTIME).tv_nsec; +} + +static void method_config_table_destroy(method_config_table* table) { + for (size_t i = 0; i < GPR_ARRAY_SIZE(table->entries); ++i) { + method_config_table_entry *entry = table->entries[i]; + while (entry != NULL) { + method_config_table_entry *next_entry = entry->next; + GRPC_MDSTR_UNREF(entry->path); + grpc_method_config_unref(entry->method_config); + gpr_free(entry); + entry = next_entry; + } + } +} + +static void method_config_table_insert(method_config_table* table, + grpc_mdstr *path, + grpc_method_config *config) { + method_config_table_entry *entry = gpr_malloc(sizeof(*entry)); + entry->path = GRPC_MDSTR_REF(path); + entry->method_config = grpc_method_config_ref(config); + entry->next = NULL; + const uint32_t hash = gpr_murmur_hash3(path, sizeof(path), table->hash_seed); + const size_t idx = hash % GPR_ARRAY_SIZE(table->entries); + if (table->entries[idx] == NULL) { + table->entries[idx] = entry; + } else { + method_config_table_entry *last_entry = table->entries[idx]; + while (last_entry->next != NULL) { + last_entry = last_entry->next; + } + last_entry->next = entry; + } +} + +static grpc_method_config *method_config_table_get(method_config_table* table, + grpc_mdstr *path) { + const uint32_t hash = gpr_murmur_hash3(path, sizeof(path), table->hash_seed); + const size_t idx = hash % GPR_ARRAY_SIZE(table->entries); + for (method_config_table_entry *entry = table->entries[idx]; + entry != NULL; entry = entry->next) { + if (entry->path == path) return entry->method_config; + } + return NULL; // Not found. +} + +/* grpc_resolver_result */ + struct grpc_resolver_result { gpr_refcount refs; grpc_addresses *addresses; char *lb_policy_name; + method_config_table method_configs; }; grpc_resolver_result *grpc_resolver_result_create(grpc_addresses *addresses, @@ -82,6 +225,7 @@ grpc_resolver_result *grpc_resolver_result_create(grpc_addresses *addresses, gpr_ref_init(&result->refs, 1); result->addresses = addresses; result->lb_policy_name = gpr_strdup(lb_policy_name); + method_config_table_init(&result->method_configs); return result; } @@ -94,6 +238,7 @@ void grpc_resolver_result_unref(grpc_exec_ctx *exec_ctx, if (gpr_unref(&result->refs)) { grpc_addresses_destroy(result->addresses); gpr_free(result->lb_policy_name); + method_config_table_destroy(&result->method_configs); gpr_free(result); } } @@ -107,3 +252,17 @@ const char *grpc_resolver_result_get_lb_policy_name( grpc_resolver_result *result) { return result->lb_policy_name; } + +void grpc_resolver_result_add_method_config( + grpc_resolver_result *result, grpc_mdstr **paths, size_t num_paths, + grpc_method_config *method_config) { + for (size_t i = 0; i < num_paths; ++i) { + method_config_table_insert(&result->method_configs, paths[i], + method_config); + } +} + +grpc_method_config *grpc_resolver_result_get_method_config( + grpc_resolver_result *result, grpc_mdstr *path) { + return method_config_table_get(&result->method_configs, path); +} diff --git a/src/core/ext/client_config/resolver_result.h b/src/core/ext/client_config/resolver_result.h index b1a34575654..877c0fb744e 100644 --- a/src/core/ext/client_config/resolver_result.h +++ b/src/core/ext/client_config/resolver_result.h @@ -40,6 +40,7 @@ #include "src/core/lib/iomgr/resolve_address.h" /** Used to represent addresses returned by the resolver. */ + typedef struct grpc_address { grpc_resolved_address address; bool is_balancer; @@ -62,7 +63,30 @@ void grpc_addresses_set_address(grpc_addresses *addresses, size_t index, void grpc_addresses_destroy(grpc_addresses *addresses); +/** Per-method configuration. */ + +typedef struct grpc_method_config grpc_method_config; + +/** Any parameter may be NULL to indicate that the value is unset. */ +grpc_method_config *grpc_method_config_create( + bool *wait_for_ready, gpr_timespec *timeout, + int32_t *max_request_message_bytes, int32_t *max_response_message_bytes); + +grpc_method_config *grpc_method_config_ref(grpc_method_config *method_config); +void grpc_method_config_unref(grpc_method_config *method_config); + +/** These methods return NULL if the requested field is unset. + The caller does NOT take ownership of the result. */ +bool *grpc_method_config_get_wait_for_ready( + grpc_method_config *method_config); +gpr_timespec* grpc_method_config_get_timeout(grpc_method_config *method_config); +int32_t* grpc_method_config_get_max_request_message_bytes( + grpc_method_config *method_config); +int32_t* grpc_method_config_get_max_response_message_bytes( + grpc_method_config *method_config); + /** Results reported from a grpc_resolver. */ + typedef struct grpc_resolver_result grpc_resolver_result; /** Takes ownership of \a addresses. */ @@ -80,4 +104,20 @@ grpc_addresses *grpc_resolver_result_get_addresses( const char *grpc_resolver_result_get_lb_policy_name( grpc_resolver_result *result); +/** Adds a method config. \a paths indicates the set of path names + for which this config applies. Each name is of one of the following + forms: + service/method -- specifies exact service and method name + service/\* -- matches all methods for the specified service + * -- matches all methods for all services + Takes new references to all elements of \a paths and to \a method_config. */ +void grpc_resolver_result_add_method_config( + grpc_resolver_result *result, grpc_mdstr **paths, size_t num_paths, + grpc_method_config *method_config); + +/** Returns NULL if the method has no config. + Caller does NOT take ownership of result. */ +grpc_method_config *grpc_resolver_result_get_method_config( + grpc_resolver_result *result, grpc_mdstr *path); + #endif /* GRPC_CORE_EXT_CLIENT_CONFIG_RESOLVER_RESULT_H */ From 673de79a0e4ad81eae7b371a5dfd3313487801c5 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Mon, 12 Sep 2016 17:56:14 -0700 Subject: [PATCH 02/48] Change method config table to use open addressing with quadratic probing. --- src/core/ext/client_config/resolver_result.c | 59 ++++++++++---------- 1 file changed, 28 insertions(+), 31 deletions(-) diff --git a/src/core/ext/client_config/resolver_result.c b/src/core/ext/client_config/resolver_result.c index 235ea5b23f3..417dc4caa8c 100644 --- a/src/core/ext/client_config/resolver_result.c +++ b/src/core/ext/client_config/resolver_result.c @@ -38,7 +38,6 @@ #include #include -#include "src/core/lib/support/murmur_hash.h" #include "src/core/lib/transport/metadata.h" /* grpc_addresses */ @@ -151,62 +150,60 @@ int32_t* grpc_method_config_get_max_response_message_bytes( typedef struct method_config_table_entry { grpc_mdstr *path; grpc_method_config *method_config; - struct method_config_table_entry *next; // Chaining for collisions. } method_config_table_entry; -#define METHOD_CONFIG_TABLE_SIZE 30 +#define METHOD_CONFIG_TABLE_SIZE 128 typedef struct method_config_table { - method_config_table_entry *entries[METHOD_CONFIG_TABLE_SIZE]; - uint32_t hash_seed; + method_config_table_entry entries[METHOD_CONFIG_TABLE_SIZE]; } method_config_table; static void method_config_table_init(method_config_table* table) { memset(table, 0, sizeof(*table)); - table->hash_seed = (uint32_t)gpr_now(GPR_CLOCK_REALTIME).tv_nsec; } static void method_config_table_destroy(method_config_table* table) { for (size_t i = 0; i < GPR_ARRAY_SIZE(table->entries); ++i) { - method_config_table_entry *entry = table->entries[i]; - while (entry != NULL) { - method_config_table_entry *next_entry = entry->next; + method_config_table_entry *entry = &table->entries[i]; + if (entry->path != NULL) { GRPC_MDSTR_UNREF(entry->path); grpc_method_config_unref(entry->method_config); - gpr_free(entry); - entry = next_entry; } } } +// Helper function for insert and get operations that performs quadratic +// probing (https://en.wikipedia.org/wiki/Quadratic_probing). +static size_t method_config_table_find_index(method_config_table* table, + grpc_mdstr *path, + bool find_empty) { + for (size_t i = 0; i < GPR_ARRAY_SIZE(table->entries); ++i) { + const size_t idx = (path->hash + i * i) % GPR_ARRAY_SIZE(table->entries); + if (table->entries[idx].path == NULL) + return find_empty ? idx : GPR_ARRAY_SIZE(table->entries); + if (table->entries[idx].path == path) + return idx; + } + return GPR_ARRAY_SIZE(table->entries) + 1; // Not found. +} + static void method_config_table_insert(method_config_table* table, grpc_mdstr *path, grpc_method_config *config) { - method_config_table_entry *entry = gpr_malloc(sizeof(*entry)); + const size_t idx = + method_config_table_find_index(table, path, true /* find_empty */); + // This can happen if the table is full. + GPR_ASSERT(idx != GPR_ARRAY_SIZE(table->entries)); + method_config_table_entry *entry = &table->entries[idx]; entry->path = GRPC_MDSTR_REF(path); entry->method_config = grpc_method_config_ref(config); - entry->next = NULL; - const uint32_t hash = gpr_murmur_hash3(path, sizeof(path), table->hash_seed); - const size_t idx = hash % GPR_ARRAY_SIZE(table->entries); - if (table->entries[idx] == NULL) { - table->entries[idx] = entry; - } else { - method_config_table_entry *last_entry = table->entries[idx]; - while (last_entry->next != NULL) { - last_entry = last_entry->next; - } - last_entry->next = entry; - } } static grpc_method_config *method_config_table_get(method_config_table* table, grpc_mdstr *path) { - const uint32_t hash = gpr_murmur_hash3(path, sizeof(path), table->hash_seed); - const size_t idx = hash % GPR_ARRAY_SIZE(table->entries); - for (method_config_table_entry *entry = table->entries[idx]; - entry != NULL; entry = entry->next) { - if (entry->path == path) return entry->method_config; - } - return NULL; // Not found. + const size_t idx = + method_config_table_find_index(table, path, false /* find_empty */); + if (idx == GPR_ARRAY_SIZE(table->entries)) return NULL; // Not found. + return table->entries[idx].method_config; } /* grpc_resolver_result */ From f0231ba07eff19085ef4cf53f4802ba23fddd2bb Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Fri, 23 Sep 2016 14:14:47 -0700 Subject: [PATCH 03/48] Fix bug from merge. --- src/core/ext/client_config/client_channel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/ext/client_config/client_channel.c b/src/core/ext/client_config/client_channel.c index e5ec69ab1a5..50a7f4467f3 100644 --- a/src/core/ext/client_config/client_channel.c +++ b/src/core/ext/client_config/client_channel.c @@ -183,7 +183,7 @@ static void on_resolver_result_changed(grpc_exec_ctx *exec_ctx, void *arg, if (chand->incoming_resolver_result != NULL) { grpc_lb_policy_args lb_policy_args; lb_policy_args.server_name = - grpc_resolver_result_get_server_name(chand->resolver_result); + grpc_resolver_result_get_server_name(chand->incoming_resolver_result); lb_policy_args.addresses = grpc_resolver_result_get_addresses(chand->incoming_resolver_result); lb_policy_args.additional_args = grpc_resolver_result_get_lb_policy_args( From 9037eff5832e060aec4f3151ee15c358abfd79a4 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Fri, 23 Sep 2016 14:14:52 -0700 Subject: [PATCH 04/48] Look for wildcard entry in service config. --- src/core/ext/client_config/resolver_result.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/core/ext/client_config/resolver_result.c b/src/core/ext/client_config/resolver_result.c index ca7937f0bc8..666f0e20539 100644 --- a/src/core/ext/client_config/resolver_result.c +++ b/src/core/ext/client_config/resolver_result.c @@ -248,5 +248,22 @@ void grpc_resolver_result_add_method_config(grpc_resolver_result* result, grpc_method_config* grpc_resolver_result_get_method_config( grpc_resolver_result* result, grpc_mdstr* path) { - return method_config_table_get(&result->method_configs, path); + grpc_method_config* method_config = + method_config_table_get(&result->method_configs, path); + // If we didn't find a match for the path, try looking for a wildcard + // entry (i.e., change "/service/method" to "/service/*"). + if (method_config == NULL) { + const char* path_str = grpc_mdstr_as_c_string(path); + const char* sep = strrchr(path_str, '/') + 1; + const size_t len = (size_t)(sep - path_str); + char buf[len + 2]; // '*' and NUL + memcpy(buf, path_str, len); + buf[len] = '*'; + buf[len + 1] = '\0'; + grpc_mdstr* wildcard_path = grpc_mdstr_from_string(buf); + method_config = + method_config_table_get(&result->method_configs, wildcard_path); + GRPC_MDSTR_UNREF(wildcard_path); + } + return method_config; } From 4c3a4688bbfd52e2a274c6382af2905901d394d1 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Fri, 23 Sep 2016 15:19:26 -0700 Subject: [PATCH 05/48] Move method config table code to its own module. --- BUILD | 8 + CMakeLists.txt | 3 + Makefile | 3 + binding.gyp | 1 + build.yaml | 2 + config.m4 | 1 + gRPC-Core.podspec | 3 + grpc.gemspec | 2 + include/grpc/impl/codegen/grpc_types.h | 3 + package.xml | 2 + src/core/ext/client_config/client_channel.c | 9 +- src/core/ext/client_config/resolver_result.c | 177 +----------------- src/core/ext/client_config/resolver_result.h | 55 +----- .../ext/resolver/dns/native/dns_resolver.c | 2 +- .../ext/resolver/sockaddr/sockaddr_resolver.c | 2 +- src/python/grpcio/grpc_core_dependencies.py | 1 + tools/doxygen/Doxyfile.core.internal | 2 + tools/run_tests/sources_and_headers.json | 3 + vsprojects/vcxproj/grpc/grpc.vcxproj | 3 + vsprojects/vcxproj/grpc/grpc.vcxproj.filters | 6 + .../grpc_unsecure/grpc_unsecure.vcxproj | 3 + .../grpc_unsecure.vcxproj.filters | 6 + 22 files changed, 77 insertions(+), 220 deletions(-) diff --git a/BUILD b/BUILD index 65f26583078..237dc30dd81 100644 --- a/BUILD +++ b/BUILD @@ -297,6 +297,7 @@ cc_library( "src/core/ext/client_config/lb_policy.h", "src/core/ext/client_config/lb_policy_factory.h", "src/core/ext/client_config/lb_policy_registry.h", + "src/core/ext/client_config/method_config.h", "src/core/ext/client_config/parse_address.h", "src/core/ext/client_config/resolver.h", "src/core/ext/client_config/resolver_factory.h", @@ -476,6 +477,7 @@ cc_library( "src/core/ext/client_config/lb_policy.c", "src/core/ext/client_config/lb_policy_factory.c", "src/core/ext/client_config/lb_policy_registry.c", + "src/core/ext/client_config/method_config.c", "src/core/ext/client_config/parse_address.c", "src/core/ext/client_config/resolver.c", "src/core/ext/client_config/resolver_factory.c", @@ -673,6 +675,7 @@ cc_library( "src/core/ext/client_config/lb_policy.h", "src/core/ext/client_config/lb_policy_factory.h", "src/core/ext/client_config/lb_policy_registry.h", + "src/core/ext/client_config/method_config.h", "src/core/ext/client_config/parse_address.h", "src/core/ext/client_config/resolver.h", "src/core/ext/client_config/resolver_factory.h", @@ -834,6 +837,7 @@ cc_library( "src/core/ext/client_config/lb_policy.c", "src/core/ext/client_config/lb_policy_factory.c", "src/core/ext/client_config/lb_policy_registry.c", + "src/core/ext/client_config/method_config.c", "src/core/ext/client_config/parse_address.c", "src/core/ext/client_config/resolver.c", "src/core/ext/client_config/resolver_factory.c", @@ -1026,6 +1030,7 @@ cc_library( "src/core/ext/client_config/lb_policy.h", "src/core/ext/client_config/lb_policy_factory.h", "src/core/ext/client_config/lb_policy_registry.h", + "src/core/ext/client_config/method_config.h", "src/core/ext/client_config/parse_address.h", "src/core/ext/client_config/resolver.h", "src/core/ext/client_config/resolver_factory.h", @@ -1180,6 +1185,7 @@ cc_library( "src/core/ext/client_config/lb_policy.c", "src/core/ext/client_config/lb_policy_factory.c", "src/core/ext/client_config/lb_policy_registry.c", + "src/core/ext/client_config/method_config.c", "src/core/ext/client_config/parse_address.c", "src/core/ext/client_config/resolver.c", "src/core/ext/client_config/resolver_factory.c", @@ -2326,6 +2332,7 @@ objc_library( "src/core/ext/client_config/lb_policy.c", "src/core/ext/client_config/lb_policy_factory.c", "src/core/ext/client_config/lb_policy_registry.c", + "src/core/ext/client_config/method_config.c", "src/core/ext/client_config/parse_address.c", "src/core/ext/client_config/resolver.c", "src/core/ext/client_config/resolver_factory.c", @@ -2525,6 +2532,7 @@ objc_library( "src/core/ext/client_config/lb_policy.h", "src/core/ext/client_config/lb_policy_factory.h", "src/core/ext/client_config/lb_policy_registry.h", + "src/core/ext/client_config/method_config.h", "src/core/ext/client_config/parse_address.h", "src/core/ext/client_config/resolver.h", "src/core/ext/client_config/resolver_factory.h", diff --git a/CMakeLists.txt b/CMakeLists.txt index d3337b56e59..460b72cf69f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -444,6 +444,7 @@ add_library(grpc src/core/ext/client_config/lb_policy.c src/core/ext/client_config/lb_policy_factory.c src/core/ext/client_config/lb_policy_registry.c + src/core/ext/client_config/method_config.c src/core/ext/client_config/parse_address.c src/core/ext/client_config/resolver.c src/core/ext/client_config/resolver_factory.c @@ -676,6 +677,7 @@ add_library(grpc_cronet src/core/ext/client_config/lb_policy.c src/core/ext/client_config/lb_policy_factory.c src/core/ext/client_config/lb_policy_registry.c + src/core/ext/client_config/method_config.c src/core/ext/client_config/parse_address.c src/core/ext/client_config/resolver.c src/core/ext/client_config/resolver_factory.c @@ -906,6 +908,7 @@ add_library(grpc_unsecure src/core/ext/client_config/lb_policy.c src/core/ext/client_config/lb_policy_factory.c src/core/ext/client_config/lb_policy_registry.c + src/core/ext/client_config/method_config.c src/core/ext/client_config/parse_address.c src/core/ext/client_config/resolver.c src/core/ext/client_config/resolver_factory.c diff --git a/Makefile b/Makefile index 4da80e01909..316ae5bfb68 100644 --- a/Makefile +++ b/Makefile @@ -2681,6 +2681,7 @@ LIBGRPC_SRC = \ src/core/ext/client_config/lb_policy.c \ src/core/ext/client_config/lb_policy_factory.c \ src/core/ext/client_config/lb_policy_registry.c \ + src/core/ext/client_config/method_config.c \ src/core/ext/client_config/parse_address.c \ src/core/ext/client_config/resolver.c \ src/core/ext/client_config/resolver_factory.c \ @@ -2931,6 +2932,7 @@ LIBGRPC_CRONET_SRC = \ src/core/ext/client_config/lb_policy.c \ src/core/ext/client_config/lb_policy_factory.c \ src/core/ext/client_config/lb_policy_registry.c \ + src/core/ext/client_config/method_config.c \ src/core/ext/client_config/parse_address.c \ src/core/ext/client_config/resolver.c \ src/core/ext/client_config/resolver_factory.c \ @@ -3388,6 +3390,7 @@ LIBGRPC_UNSECURE_SRC = \ src/core/ext/client_config/lb_policy.c \ src/core/ext/client_config/lb_policy_factory.c \ src/core/ext/client_config/lb_policy_registry.c \ + src/core/ext/client_config/method_config.c \ src/core/ext/client_config/parse_address.c \ src/core/ext/client_config/resolver.c \ src/core/ext/client_config/resolver_factory.c \ diff --git a/binding.gyp b/binding.gyp index 4bbef1e6b26..25b571d2a62 100644 --- a/binding.gyp +++ b/binding.gyp @@ -719,6 +719,7 @@ 'src/core/ext/client_config/lb_policy.c', 'src/core/ext/client_config/lb_policy_factory.c', 'src/core/ext/client_config/lb_policy_registry.c', + 'src/core/ext/client_config/method_config.c', 'src/core/ext/client_config/parse_address.c', 'src/core/ext/client_config/resolver.c', 'src/core/ext/client_config/resolver_factory.c', diff --git a/build.yaml b/build.yaml index 3701c0d8149..67701058df4 100644 --- a/build.yaml +++ b/build.yaml @@ -354,6 +354,7 @@ filegroups: - src/core/ext/client_config/lb_policy.h - src/core/ext/client_config/lb_policy_factory.h - src/core/ext/client_config/lb_policy_registry.h + - src/core/ext/client_config/method_config.h - src/core/ext/client_config/parse_address.h - src/core/ext/client_config/resolver.h - src/core/ext/client_config/resolver_factory.h @@ -374,6 +375,7 @@ filegroups: - src/core/ext/client_config/lb_policy.c - src/core/ext/client_config/lb_policy_factory.c - src/core/ext/client_config/lb_policy_registry.c + - src/core/ext/client_config/method_config.c - src/core/ext/client_config/parse_address.c - src/core/ext/client_config/resolver.c - src/core/ext/client_config/resolver_factory.c diff --git a/config.m4 b/config.m4 index 493ebe9c82b..d41ce162426 100644 --- a/config.m4 +++ b/config.m4 @@ -238,6 +238,7 @@ if test "$PHP_GRPC" != "no"; then src/core/ext/client_config/lb_policy.c \ src/core/ext/client_config/lb_policy_factory.c \ src/core/ext/client_config/lb_policy_registry.c \ + src/core/ext/client_config/method_config.c \ src/core/ext/client_config/parse_address.c \ src/core/ext/client_config/resolver.c \ src/core/ext/client_config/resolver_factory.c \ diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec index dbf41ecd292..b48c93310ac 100644 --- a/gRPC-Core.podspec +++ b/gRPC-Core.podspec @@ -384,6 +384,7 @@ Pod::Spec.new do |s| 'src/core/ext/client_config/lb_policy.h', 'src/core/ext/client_config/lb_policy_factory.h', 'src/core/ext/client_config/lb_policy_registry.h', + 'src/core/ext/client_config/method_config.h', 'src/core/ext/client_config/parse_address.h', 'src/core/ext/client_config/resolver.h', 'src/core/ext/client_config/resolver_factory.h', @@ -567,6 +568,7 @@ Pod::Spec.new do |s| 'src/core/ext/client_config/lb_policy.c', 'src/core/ext/client_config/lb_policy_factory.c', 'src/core/ext/client_config/lb_policy_registry.c', + 'src/core/ext/client_config/method_config.c', 'src/core/ext/client_config/parse_address.c', 'src/core/ext/client_config/resolver.c', 'src/core/ext/client_config/resolver_factory.c', @@ -755,6 +757,7 @@ Pod::Spec.new do |s| 'src/core/ext/client_config/lb_policy.h', 'src/core/ext/client_config/lb_policy_factory.h', 'src/core/ext/client_config/lb_policy_registry.h', + 'src/core/ext/client_config/method_config.h', 'src/core/ext/client_config/parse_address.h', 'src/core/ext/client_config/resolver.h', 'src/core/ext/client_config/resolver_factory.h', diff --git a/grpc.gemspec b/grpc.gemspec index 7fefaadd655..3dbb1557148 100755 --- a/grpc.gemspec +++ b/grpc.gemspec @@ -304,6 +304,7 @@ Gem::Specification.new do |s| s.files += %w( src/core/ext/client_config/lb_policy.h ) s.files += %w( src/core/ext/client_config/lb_policy_factory.h ) s.files += %w( src/core/ext/client_config/lb_policy_registry.h ) + s.files += %w( src/core/ext/client_config/method_config.h ) s.files += %w( src/core/ext/client_config/parse_address.h ) s.files += %w( src/core/ext/client_config/resolver.h ) s.files += %w( src/core/ext/client_config/resolver_factory.h ) @@ -487,6 +488,7 @@ Gem::Specification.new do |s| s.files += %w( src/core/ext/client_config/lb_policy.c ) s.files += %w( src/core/ext/client_config/lb_policy_factory.c ) s.files += %w( src/core/ext/client_config/lb_policy_registry.c ) + s.files += %w( src/core/ext/client_config/method_config.c ) s.files += %w( src/core/ext/client_config/parse_address.c ) s.files += %w( src/core/ext/client_config/resolver.c ) s.files += %w( src/core/ext/client_config/resolver_factory.c ) diff --git a/include/grpc/impl/codegen/grpc_types.h b/include/grpc/impl/codegen/grpc_types.h index a8e8ebe6ea9..d95f32f1fad 100644 --- a/include/grpc/impl/codegen/grpc_types.h +++ b/include/grpc/impl/codegen/grpc_types.h @@ -196,6 +196,9 @@ typedef struct { #define GRPC_ARG_MAX_METADATA_SIZE "grpc.max_metadata_size" /** If non-zero, allow the use of SO_REUSEPORT if it's available (default 1) */ #define GRPC_ARG_ALLOW_REUSEPORT "grpc.so_reuseport" +/** Service config data, to be passed to subchannels. + Not intended for external use. */ +#define GRPC_ARG_SERVICE_CONFIG "grpc.service_config" /** \} */ /** Result of a grpc call. If the caller satisfies the prerequisites of a diff --git a/package.xml b/package.xml index 3fd1472c809..8eb4bc35be0 100644 --- a/package.xml +++ b/package.xml @@ -311,6 +311,7 @@ + @@ -494,6 +495,7 @@ + diff --git a/src/core/ext/client_config/client_channel.c b/src/core/ext/client_config/client_channel.c index 50a7f4467f3..73e62fcbbfd 100644 --- a/src/core/ext/client_config/client_channel.c +++ b/src/core/ext/client_config/client_channel.c @@ -511,8 +511,13 @@ static void subchannel_ready(grpc_exec_ctx *exec_ctx, void *arg, } else { /* Get method config. */ // FIXME: need to actually use the config data! - calld->method_config = grpc_resolver_result_get_method_config( - chand->current_resolver_result, calld->path); +// FIXME: think about refcounting vs. atomicity here + grpc_method_config_table* table = grpc_resolver_result_get_method_configs( + chand->current_resolver_result); + if (table != NULL) { + calld->method_config = grpc_method_config_table_get_method_config( + table, calld->path); + } /* Create call on subchannel. */ grpc_subchannel_call *subchannel_call = NULL; grpc_error *new_error = grpc_connected_subchannel_create_call( diff --git a/src/core/ext/client_config/resolver_result.c b/src/core/ext/client_config/resolver_result.c index 666f0e20539..5c5ffb2635f 100644 --- a/src/core/ext/client_config/resolver_result.c +++ b/src/core/ext/client_config/resolver_result.c @@ -39,141 +39,6 @@ #include "src/core/lib/transport/metadata.h" #include "src/core/lib/channel/channel_args.h" -// -// grpc_method_config -// - -struct grpc_method_config { - gpr_refcount refs; - bool* wait_for_ready; - gpr_timespec* timeout; - int32_t* max_request_message_bytes; - int32_t* max_response_message_bytes; -}; - -grpc_method_config* grpc_method_config_create( - bool* wait_for_ready, gpr_timespec* timeout, - int32_t* max_request_message_bytes, int32_t* max_response_message_bytes) { - grpc_method_config* config = gpr_malloc(sizeof(*config)); - memset(config, 0, sizeof(*config)); - gpr_ref_init(&config->refs, 1); - if (wait_for_ready != NULL) { - config->wait_for_ready = gpr_malloc(sizeof(*wait_for_ready)); - *config->wait_for_ready = *wait_for_ready; - } - if (timeout != NULL) { - config->timeout = gpr_malloc(sizeof(*timeout)); - *config->timeout = *timeout; - } - if (max_request_message_bytes != NULL) { - config->max_request_message_bytes = - gpr_malloc(sizeof(*max_request_message_bytes)); - *config->max_request_message_bytes = *max_request_message_bytes; - } - if (max_response_message_bytes != NULL) { - config->max_response_message_bytes = - gpr_malloc(sizeof(*max_response_message_bytes)); - *config->max_response_message_bytes = *max_response_message_bytes; - } - return config; -} - -grpc_method_config* grpc_method_config_ref(grpc_method_config* method_config) { - gpr_ref(&method_config->refs); - return method_config; -} - -void grpc_method_config_unref(grpc_method_config* method_config) { - if (gpr_unref(&method_config->refs)) { - gpr_free(method_config->wait_for_ready); - gpr_free(method_config->timeout); - gpr_free(method_config->max_request_message_bytes); - gpr_free(method_config->max_response_message_bytes); - gpr_free(method_config); - } -} - -bool* grpc_method_config_get_wait_for_ready(grpc_method_config* method_config) { - return method_config->wait_for_ready; -} - -gpr_timespec* grpc_method_config_get_timeout( - grpc_method_config* method_config) { - return method_config->timeout; -} - -int32_t* grpc_method_config_get_max_request_message_bytes( - grpc_method_config* method_config) { - return method_config->max_request_message_bytes; -} - -int32_t* grpc_method_config_get_max_response_message_bytes( - grpc_method_config* method_config) { - return method_config->max_response_message_bytes; -} - -// -// method_config_table -// - -typedef struct method_config_table_entry { - grpc_mdstr* path; - grpc_method_config* method_config; -} method_config_table_entry; - -#define METHOD_CONFIG_TABLE_SIZE 128 -typedef struct method_config_table { - method_config_table_entry entries[METHOD_CONFIG_TABLE_SIZE]; -} method_config_table; - -static void method_config_table_init(method_config_table* table) { - memset(table, 0, sizeof(*table)); -} - -static void method_config_table_destroy(method_config_table* table) { - for (size_t i = 0; i < GPR_ARRAY_SIZE(table->entries); ++i) { - method_config_table_entry* entry = &table->entries[i]; - if (entry->path != NULL) { - GRPC_MDSTR_UNREF(entry->path); - grpc_method_config_unref(entry->method_config); - } - } -} - -// Helper function for insert and get operations that performs quadratic -// probing (https://en.wikipedia.org/wiki/Quadratic_probing). -static size_t method_config_table_find_index(method_config_table* table, - grpc_mdstr* path, - bool find_empty) { - for (size_t i = 0; i < GPR_ARRAY_SIZE(table->entries); ++i) { - const size_t idx = (path->hash + i * i) % GPR_ARRAY_SIZE(table->entries); - if (table->entries[idx].path == NULL) - return find_empty ? idx : GPR_ARRAY_SIZE(table->entries); - if (table->entries[idx].path == path) return idx; - } - return GPR_ARRAY_SIZE(table->entries) + 1; // Not found. -} - -static void method_config_table_insert(method_config_table* table, - grpc_mdstr* path, - grpc_method_config* config) { - const size_t idx = - method_config_table_find_index(table, path, true /* find_empty */); - // This can happen if the table is full. - GPR_ASSERT(idx != GPR_ARRAY_SIZE(table->entries)); - method_config_table_entry* entry = &table->entries[idx]; - entry->path = GRPC_MDSTR_REF(path); - entry->method_config = grpc_method_config_ref(config); -} - -static grpc_method_config* method_config_table_get(method_config_table* table, - grpc_mdstr* path) { - const size_t idx = - method_config_table_find_index(table, path, false /* find_empty */); - if (idx == GPR_ARRAY_SIZE(table->entries)) return NULL; // Not found. - return table->entries[idx].method_config; -} - // // grpc_resolver_result // @@ -184,12 +49,13 @@ struct grpc_resolver_result { grpc_lb_addresses* addresses; char* lb_policy_name; grpc_channel_args* lb_policy_args; - method_config_table method_configs; + grpc_method_config_table* method_configs; }; grpc_resolver_result* grpc_resolver_result_create( const char* server_name, grpc_lb_addresses* addresses, - const char* lb_policy_name, grpc_channel_args* lb_policy_args) { + const char* lb_policy_name, grpc_channel_args* lb_policy_args, + grpc_method_config_table* method_configs) { grpc_resolver_result* result = gpr_malloc(sizeof(*result)); memset(result, 0, sizeof(*result)); gpr_ref_init(&result->refs, 1); @@ -197,7 +63,7 @@ grpc_resolver_result* grpc_resolver_result_create( result->addresses = addresses; result->lb_policy_name = gpr_strdup(lb_policy_name); result->lb_policy_args = lb_policy_args; - method_config_table_init(&result->method_configs); + result->method_configs = grpc_method_config_table_ref(method_configs); return result; } @@ -212,7 +78,7 @@ void grpc_resolver_result_unref(grpc_exec_ctx* exec_ctx, grpc_lb_addresses_destroy(result->addresses, NULL /* user_data_destroy */); gpr_free(result->lb_policy_name); grpc_channel_args_destroy(result->lb_policy_args); - method_config_table_destroy(&result->method_configs); + grpc_method_config_table_unref(result->method_configs); gpr_free(result); } } @@ -236,34 +102,7 @@ grpc_channel_args* grpc_resolver_result_get_lb_policy_args( return result->lb_policy_args; } -void grpc_resolver_result_add_method_config(grpc_resolver_result* result, - grpc_mdstr** paths, - size_t num_paths, - grpc_method_config* method_config) { - for (size_t i = 0; i < num_paths; ++i) { - method_config_table_insert(&result->method_configs, paths[i], - method_config); - } -} - -grpc_method_config* grpc_resolver_result_get_method_config( - grpc_resolver_result* result, grpc_mdstr* path) { - grpc_method_config* method_config = - method_config_table_get(&result->method_configs, path); - // If we didn't find a match for the path, try looking for a wildcard - // entry (i.e., change "/service/method" to "/service/*"). - if (method_config == NULL) { - const char* path_str = grpc_mdstr_as_c_string(path); - const char* sep = strrchr(path_str, '/') + 1; - const size_t len = (size_t)(sep - path_str); - char buf[len + 2]; // '*' and NUL - memcpy(buf, path_str, len); - buf[len] = '*'; - buf[len + 1] = '\0'; - grpc_mdstr* wildcard_path = grpc_mdstr_from_string(buf); - method_config = - method_config_table_get(&result->method_configs, wildcard_path); - GRPC_MDSTR_UNREF(wildcard_path); - } - return method_config; +grpc_method_config_table* grpc_resolver_result_get_method_configs( + grpc_resolver_result* result) { + return result->method_configs; } diff --git a/src/core/ext/client_config/resolver_result.h b/src/core/ext/client_config/resolver_result.h index e954fc12c30..e6127f1d6d4 100644 --- a/src/core/ext/client_config/resolver_result.h +++ b/src/core/ext/client_config/resolver_result.h @@ -33,6 +33,7 @@ #define GRPC_CORE_EXT_CLIENT_CONFIG_RESOLVER_RESULT_H #include "src/core/ext/client_config/lb_policy_factory.h" +#include "src/core/ext/client_config/method_config.h" #include "src/core/lib/iomgr/resolve_address.h" // TODO(roth, ctiller): In the long term, we are considering replacing @@ -45,68 +46,28 @@ // grpc_channel_args such to a hash table or AVL or some other data // structure that does not require linear search to find keys. -/// Per-method configuration. - -typedef struct grpc_method_config grpc_method_config; - -/// Any parameter may be NULL to indicate that the value is unset. -grpc_method_config* grpc_method_config_create( - bool* wait_for_ready, gpr_timespec* timeout, - int32_t* max_request_message_bytes, int32_t* max_response_message_bytes); - -grpc_method_config* grpc_method_config_ref(grpc_method_config* method_config); -void grpc_method_config_unref(grpc_method_config* method_config); - -/// These methods return NULL if the requested field is unset. -/// The caller does NOT take ownership of the result. -bool* grpc_method_config_get_wait_for_ready(grpc_method_config* method_config); -gpr_timespec* grpc_method_config_get_timeout(grpc_method_config* method_config); -int32_t* grpc_method_config_get_max_request_message_bytes( - grpc_method_config* method_config); -int32_t* grpc_method_config_get_max_response_message_bytes( - grpc_method_config* method_config); - /// Results reported from a grpc_resolver. typedef struct grpc_resolver_result grpc_resolver_result; -/// Takes ownership of \a addresses and \a lb_policy_args. +/// Takes ownership of \a addresses, \a lb_policy_args. grpc_resolver_result* grpc_resolver_result_create( const char* server_name, grpc_lb_addresses* addresses, - const char* lb_policy_name, grpc_channel_args* lb_policy_args); + const char* lb_policy_name, grpc_channel_args* lb_policy_args, + grpc_method_config_table* method_configs); + void grpc_resolver_result_ref(grpc_resolver_result* result); void grpc_resolver_result_unref(grpc_exec_ctx* exec_ctx, grpc_resolver_result* result); -/// Caller does NOT take ownership of result. +/// Accessors. Caller does NOT take ownership of results. const char* grpc_resolver_result_get_server_name(grpc_resolver_result* result); - -/// Caller does NOT take ownership of result. grpc_lb_addresses* grpc_resolver_result_get_addresses( grpc_resolver_result* result); - -/// Caller does NOT take ownership of result. const char* grpc_resolver_result_get_lb_policy_name( grpc_resolver_result* result); - -/// Caller does NOT take ownership of result. grpc_channel_args* grpc_resolver_result_get_lb_policy_args( grpc_resolver_result* result); - -/// Adds a method config. \a paths indicates the set of path names -/// for which this config applies. Each name is of one of the following -/// forms: -/// service/method -- specifies exact service and method name -/// service/* -- matches all methods for the specified service -/// * -- matches all methods for all services -/// Takes new references to all elements of \a paths and to \a method_config. -void grpc_resolver_result_add_method_config(grpc_resolver_result* result, - grpc_mdstr** paths, - size_t num_paths, - grpc_method_config* method_config); - -/// Returns NULL if the method has no config. -/// Caller does NOT take ownership of result. -grpc_method_config* grpc_resolver_result_get_method_config( - grpc_resolver_result* result, grpc_mdstr* path); +grpc_method_config_table* grpc_resolver_result_get_method_configs( + grpc_resolver_result* result); #endif /* GRPC_CORE_EXT_CLIENT_CONFIG_RESOLVER_RESULT_H */ diff --git a/src/core/ext/resolver/dns/native/dns_resolver.c b/src/core/ext/resolver/dns/native/dns_resolver.c index e8ac1b12ae8..879e26f7d94 100644 --- a/src/core/ext/resolver/dns/native/dns_resolver.c +++ b/src/core/ext/resolver/dns/native/dns_resolver.c @@ -181,7 +181,7 @@ static void dns_on_resolved(grpc_exec_ctx *exec_ctx, void *arg, } grpc_resolved_addresses_destroy(r->addresses); result = grpc_resolver_result_create(r->target_name, addresses, - r->lb_policy_name, NULL); + r->lb_policy_name, NULL, NULL); } else { gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC); gpr_timespec next_try = gpr_backoff_step(&r->backoff_state, now); diff --git a/src/core/ext/resolver/sockaddr/sockaddr_resolver.c b/src/core/ext/resolver/sockaddr/sockaddr_resolver.c index 74d2015e5c2..61be1b3c256 100644 --- a/src/core/ext/resolver/sockaddr/sockaddr_resolver.c +++ b/src/core/ext/resolver/sockaddr/sockaddr_resolver.c @@ -122,7 +122,7 @@ static void sockaddr_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx, r->published = true; *r->target_result = grpc_resolver_result_create( "", grpc_lb_addresses_copy(r->addresses, NULL /* user_data_copy */), - r->lb_policy_name, NULL); + r->lb_policy_name, NULL, NULL); grpc_exec_ctx_sched(exec_ctx, r->next_completion, GRPC_ERROR_NONE, NULL); r->next_completion = NULL; } diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py index d87f8b57b0a..a534bf376a7 100644 --- a/src/python/grpcio/grpc_core_dependencies.py +++ b/src/python/grpcio/grpc_core_dependencies.py @@ -232,6 +232,7 @@ CORE_SOURCE_FILES = [ 'src/core/ext/client_config/lb_policy.c', 'src/core/ext/client_config/lb_policy_factory.c', 'src/core/ext/client_config/lb_policy_registry.c', + 'src/core/ext/client_config/method_config.c', 'src/core/ext/client_config/parse_address.c', 'src/core/ext/client_config/resolver.c', 'src/core/ext/client_config/resolver_factory.c', diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal index c8c683e933a..77ebfe43f1e 100644 --- a/tools/doxygen/Doxyfile.core.internal +++ b/tools/doxygen/Doxyfile.core.internal @@ -921,6 +921,7 @@ src/core/ext/client_config/initial_connect_string.h \ src/core/ext/client_config/lb_policy.h \ src/core/ext/client_config/lb_policy_factory.h \ src/core/ext/client_config/lb_policy_registry.h \ +src/core/ext/client_config/method_config.h \ src/core/ext/client_config/parse_address.h \ src/core/ext/client_config/resolver.h \ src/core/ext/client_config/resolver_factory.h \ @@ -1104,6 +1105,7 @@ src/core/ext/client_config/initial_connect_string.c \ src/core/ext/client_config/lb_policy.c \ src/core/ext/client_config/lb_policy_factory.c \ src/core/ext/client_config/lb_policy_registry.c \ +src/core/ext/client_config/method_config.c \ src/core/ext/client_config/parse_address.c \ src/core/ext/client_config/resolver.c \ src/core/ext/client_config/resolver_factory.c \ diff --git a/tools/run_tests/sources_and_headers.json b/tools/run_tests/sources_and_headers.json index 1b8f19a298d..684ce7a5d4d 100644 --- a/tools/run_tests/sources_and_headers.json +++ b/tools/run_tests/sources_and_headers.json @@ -6256,6 +6256,7 @@ "src/core/ext/client_config/lb_policy.h", "src/core/ext/client_config/lb_policy_factory.h", "src/core/ext/client_config/lb_policy_registry.h", + "src/core/ext/client_config/method_config.h", "src/core/ext/client_config/parse_address.h", "src/core/ext/client_config/resolver.h", "src/core/ext/client_config/resolver_factory.h", @@ -6287,6 +6288,8 @@ "src/core/ext/client_config/lb_policy_factory.h", "src/core/ext/client_config/lb_policy_registry.c", "src/core/ext/client_config/lb_policy_registry.h", + "src/core/ext/client_config/method_config.c", + "src/core/ext/client_config/method_config.h", "src/core/ext/client_config/parse_address.c", "src/core/ext/client_config/parse_address.h", "src/core/ext/client_config/resolver.c", diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj b/vsprojects/vcxproj/grpc/grpc.vcxproj index 2e81171a0cb..d18f25955d8 100644 --- a/vsprojects/vcxproj/grpc/grpc.vcxproj +++ b/vsprojects/vcxproj/grpc/grpc.vcxproj @@ -430,6 +430,7 @@ + @@ -770,6 +771,8 @@ + + diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters index 5c509dd9684..59238915d9f 100644 --- a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters +++ b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters @@ -466,6 +466,9 @@ src\core\ext\client_config + + src\core\ext\client_config + src\core\ext\client_config @@ -1070,6 +1073,9 @@ src\core\ext\client_config + + src\core\ext\client_config + src\core\ext\client_config diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj index c681f7ffab4..9e40ae690b7 100644 --- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj +++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj @@ -396,6 +396,7 @@ + @@ -686,6 +687,8 @@ + + diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters index c966304b93f..6c7600a305e 100644 --- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters +++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters @@ -391,6 +391,9 @@ src\core\ext\client_config + + src\core\ext\client_config + src\core\ext\client_config @@ -908,6 +911,9 @@ src\core\ext\client_config + + src\core\ext\client_config + src\core\ext\client_config From 2e8920873d41b05a61378b1a1ea61f9ac051df15 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Fri, 23 Sep 2016 15:19:54 -0700 Subject: [PATCH 06/48] Add new files missed in last commit. --- src/core/ext/client_config/method_config.c | 214 +++++++++++++++++++++ src/core/ext/client_config/method_config.h | 85 ++++++++ 2 files changed, 299 insertions(+) create mode 100644 src/core/ext/client_config/method_config.c create mode 100644 src/core/ext/client_config/method_config.h diff --git a/src/core/ext/client_config/method_config.c b/src/core/ext/client_config/method_config.c new file mode 100644 index 00000000000..e3589153fb6 --- /dev/null +++ b/src/core/ext/client_config/method_config.c @@ -0,0 +1,214 @@ +// +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +#include "src/core/ext/client_config/method_config.h" + +#include + +#include +#include +#include + +#include "src/core/lib/transport/metadata.h" + +// +// grpc_method_config +// + +struct grpc_method_config { + gpr_refcount refs; + bool* wait_for_ready; + gpr_timespec* timeout; + int32_t* max_request_message_bytes; + int32_t* max_response_message_bytes; +}; + +grpc_method_config* grpc_method_config_create( + bool* wait_for_ready, gpr_timespec* timeout, + int32_t* max_request_message_bytes, int32_t* max_response_message_bytes) { + grpc_method_config* config = gpr_malloc(sizeof(*config)); + memset(config, 0, sizeof(*config)); + gpr_ref_init(&config->refs, 1); + if (wait_for_ready != NULL) { + config->wait_for_ready = gpr_malloc(sizeof(*wait_for_ready)); + *config->wait_for_ready = *wait_for_ready; + } + if (timeout != NULL) { + config->timeout = gpr_malloc(sizeof(*timeout)); + *config->timeout = *timeout; + } + if (max_request_message_bytes != NULL) { + config->max_request_message_bytes = + gpr_malloc(sizeof(*max_request_message_bytes)); + *config->max_request_message_bytes = *max_request_message_bytes; + } + if (max_response_message_bytes != NULL) { + config->max_response_message_bytes = + gpr_malloc(sizeof(*max_response_message_bytes)); + *config->max_response_message_bytes = *max_response_message_bytes; + } + return config; +} + +grpc_method_config* grpc_method_config_ref(grpc_method_config* method_config) { + gpr_ref(&method_config->refs); + return method_config; +} + +void grpc_method_config_unref(grpc_method_config* method_config) { + if (gpr_unref(&method_config->refs)) { + gpr_free(method_config->wait_for_ready); + gpr_free(method_config->timeout); + gpr_free(method_config->max_request_message_bytes); + gpr_free(method_config->max_response_message_bytes); + gpr_free(method_config); + } +} + +bool* grpc_method_config_get_wait_for_ready(grpc_method_config* method_config) { + return method_config->wait_for_ready; +} + +gpr_timespec* grpc_method_config_get_timeout( + grpc_method_config* method_config) { + return method_config->timeout; +} + +int32_t* grpc_method_config_get_max_request_message_bytes( + grpc_method_config* method_config) { + return method_config->max_request_message_bytes; +} + +int32_t* grpc_method_config_get_max_response_message_bytes( + grpc_method_config* method_config) { + return method_config->max_response_message_bytes; +} + +// +// grpc_method_config_table +// + +typedef struct grpc_method_config_table_entry { + grpc_mdstr* path; + grpc_method_config* method_config; +} grpc_method_config_table_entry; + +#define METHOD_CONFIG_TABLE_SIZE 128 +struct grpc_method_config_table { + gpr_refcount refs; + grpc_method_config_table_entry entries[METHOD_CONFIG_TABLE_SIZE]; +}; + +grpc_method_config_table* grpc_method_config_table_create() { + grpc_method_config_table* table = gpr_malloc(sizeof(*table)); + memset(table, 0, sizeof(*table)); + gpr_ref_init(&table->refs, 1); + return table; +} + +grpc_method_config_table* grpc_method_config_table_ref( + grpc_method_config_table* table) { + if (table != NULL) gpr_ref(&table->refs); + return table; +} + +void grpc_method_config_table_unref(grpc_method_config_table* table) { + if (table != NULL && gpr_unref(&table->refs)) { + for (size_t i = 0; i < GPR_ARRAY_SIZE(table->entries); ++i) { + grpc_method_config_table_entry* entry = &table->entries[i]; + if (entry->path != NULL) { + GRPC_MDSTR_UNREF(entry->path); + grpc_method_config_unref(entry->method_config); + } + } + } +} + +// Helper function for insert and get operations that performs quadratic +// probing (https://en.wikipedia.org/wiki/Quadratic_probing). +static size_t grpc_method_config_table_find_index( + grpc_method_config_table* table, grpc_mdstr* path, bool find_empty) { + for (size_t i = 0; i < GPR_ARRAY_SIZE(table->entries); ++i) { + const size_t idx = (path->hash + i * i) % GPR_ARRAY_SIZE(table->entries); + if (table->entries[idx].path == NULL) + return find_empty ? idx : GPR_ARRAY_SIZE(table->entries); + if (table->entries[idx].path == path) return idx; + } + return GPR_ARRAY_SIZE(table->entries) + 1; // Not found. +} + +static void grpc_method_config_table_insert(grpc_method_config_table* table, + grpc_mdstr* path, + grpc_method_config* config) { + const size_t idx = + grpc_method_config_table_find_index(table, path, true /* find_empty */); + // This can happen if the table is full. + GPR_ASSERT(idx != GPR_ARRAY_SIZE(table->entries)); + grpc_method_config_table_entry* entry = &table->entries[idx]; + entry->path = GRPC_MDSTR_REF(path); + entry->method_config = grpc_method_config_ref(config); +} + +static grpc_method_config* grpc_method_config_table_get( + grpc_method_config_table* table, grpc_mdstr* path) { + const size_t idx = + grpc_method_config_table_find_index(table, path, false /* find_empty */); + if (idx == GPR_ARRAY_SIZE(table->entries)) return NULL; // Not found. + return table->entries[idx].method_config; +} + +void grpc_method_config_table_add_method_config( + grpc_method_config_table* table, grpc_mdstr** paths, size_t num_paths, + grpc_method_config* method_config) { + for (size_t i = 0; i < num_paths; ++i) { + grpc_method_config_table_insert(table, paths[i], method_config); + } +} + +grpc_method_config* grpc_method_config_table_get_method_config( + grpc_method_config_table* table, grpc_mdstr* path) { + grpc_method_config* method_config = grpc_method_config_table_get(table, path); + // If we didn't find a match for the path, try looking for a wildcard + // entry (i.e., change "/service/method" to "/service/*"). + if (method_config == NULL) { + const char* path_str = grpc_mdstr_as_c_string(path); + const char* sep = strrchr(path_str, '/') + 1; + const size_t len = (size_t)(sep - path_str); + char buf[len + 2]; // '*' and NUL + memcpy(buf, path_str, len); + buf[len] = '*'; + buf[len + 1] = '\0'; + grpc_mdstr* wildcard_path = grpc_mdstr_from_string(buf); + method_config = grpc_method_config_table_get(table, wildcard_path); + GRPC_MDSTR_UNREF(wildcard_path); + } + return grpc_method_config_ref(method_config); +} diff --git a/src/core/ext/client_config/method_config.h b/src/core/ext/client_config/method_config.h new file mode 100644 index 00000000000..9490e296b27 --- /dev/null +++ b/src/core/ext/client_config/method_config.h @@ -0,0 +1,85 @@ +// +// Copyright 2016, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +#ifndef GRPC_CORE_EXT_CLIENT_CONFIG_METHOD_CONFIG_H +#define GRPC_CORE_EXT_CLIENT_CONFIG_METHOD_CONFIG_H + +#include + +#include + +#include "src/core/lib/transport/metadata.h" + +/// Per-method configuration. +typedef struct grpc_method_config grpc_method_config; + +/// Any parameter may be NULL to indicate that the value is unset. +grpc_method_config* grpc_method_config_create( + bool* wait_for_ready, gpr_timespec* timeout, + int32_t* max_request_message_bytes, int32_t* max_response_message_bytes); + +grpc_method_config* grpc_method_config_ref(grpc_method_config* method_config); +void grpc_method_config_unref(grpc_method_config* method_config); + +/// These methods return NULL if the requested field is unset. +/// The caller does NOT take ownership of the result. +bool* grpc_method_config_get_wait_for_ready(grpc_method_config* method_config); +gpr_timespec* grpc_method_config_get_timeout(grpc_method_config* method_config); +int32_t* grpc_method_config_get_max_request_message_bytes( + grpc_method_config* method_config); +int32_t* grpc_method_config_get_max_response_message_bytes( + grpc_method_config* method_config); + +/// A table of method configs. +typedef struct grpc_method_config_table grpc_method_config_table; + +grpc_method_config_table* grpc_method_config_table_create(); + +grpc_method_config_table* grpc_method_config_table_ref( + grpc_method_config_table* table); +void grpc_method_config_table_unref(grpc_method_config_table* table); + +/// Adds \a method_config to \a table. \a paths indicates the set of path +/// names for which this config applies. Each name is of one of the +/// following forms: +/// service/method -- specifies exact service and method name +/// service/* -- matches all methods for the specified service +/// Takes new references to all elements of \a paths and to \a method_config. +void grpc_method_config_table_add_method_config( + grpc_method_config_table* table, grpc_mdstr** paths, size_t num_paths, + grpc_method_config* method_config); + +/// Returns NULL if the method has no config. +/// Caller owns a reference to result. +grpc_method_config* grpc_method_config_table_get_method_config( + grpc_method_config_table* table, grpc_mdstr* path); + +#endif /* GRPC_CORE_EXT_CLIENT_CONFIG_METHOD_CONFIG_H */ From 046cf7646918b19a8956e20f7e28e7422a6f29cd Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Mon, 26 Sep 2016 11:13:51 -0700 Subject: [PATCH 07/48] Encode method config table in channel args instead of in resolver result. --- src/core/ext/client_config/client_channel.c | 65 +++++++++-------- src/core/ext/client_config/method_config.c | 71 +++++++++++++++++++ src/core/ext/client_config/method_config.h | 5 ++ src/core/ext/client_config/resolver_result.c | 11 +-- src/core/ext/client_config/resolver_result.h | 6 +- src/core/ext/lb_policy/grpclb/grpclb.c | 5 ++ .../ext/lb_policy/pick_first/pick_first.c | 1 + .../ext/lb_policy/round_robin/round_robin.c | 1 + .../ext/resolver/dns/native/dns_resolver.c | 2 +- .../ext/resolver/sockaddr/sockaddr_resolver.c | 2 +- src/core/lib/channel/channel_args.c | 10 +++ src/core/lib/channel/channel_args.h | 6 ++ 12 files changed, 137 insertions(+), 48 deletions(-) diff --git a/src/core/ext/client_config/client_channel.c b/src/core/ext/client_config/client_channel.c index 73e62fcbbfd..96c8c62c044 100644 --- a/src/core/ext/client_config/client_channel.c +++ b/src/core/ext/client_config/client_channel.c @@ -43,6 +43,7 @@ #include #include "src/core/ext/client_config/lb_policy_registry.h" +#include "src/core/ext/client_config/method_config.h" #include "src/core/ext/client_config/subchannel.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/channel/connected_channel.h" @@ -70,15 +71,14 @@ typedef struct client_channel_channel_data { /** client channel factory */ grpc_client_channel_factory *client_channel_factory; - /** mutex protecting client configuration, including all - variables below in this data structure */ + /** mutex protecting all variables below in this data structure */ gpr_mu mu; - /** currently active load balancer - guarded by mu */ + /** currently active load balancer */ grpc_lb_policy *lb_policy; - /** incoming resolver result - set by resolver.next(), guarded by mu */ - grpc_resolver_result *incoming_resolver_result; - /** current resolver result */ - grpc_resolver_result *current_resolver_result; + /** method config table */ + grpc_method_config_table *method_config_table; + /** incoming resolver result - set by resolver.next() */ + grpc_resolver_result *resolver_result; /** a list of closures that are all waiting for config to come in */ grpc_closure_list waiting_for_config_closures; /** resolver callback */ @@ -176,23 +176,23 @@ static void on_resolver_result_changed(grpc_exec_ctx *exec_ctx, void *arg, channel_data *chand = arg; grpc_lb_policy *lb_policy = NULL; grpc_lb_policy *old_lb_policy; + grpc_method_config_table *method_config_table = NULL; grpc_connectivity_state state = GRPC_CHANNEL_TRANSIENT_FAILURE; bool exit_idle = false; grpc_error *state_error = GRPC_ERROR_CREATE("No load balancing policy"); - if (chand->incoming_resolver_result != NULL) { + if (chand->resolver_result != NULL) { grpc_lb_policy_args lb_policy_args; lb_policy_args.server_name = - grpc_resolver_result_get_server_name(chand->incoming_resolver_result); + grpc_resolver_result_get_server_name(chand->resolver_result); lb_policy_args.addresses = - grpc_resolver_result_get_addresses(chand->incoming_resolver_result); - lb_policy_args.additional_args = grpc_resolver_result_get_lb_policy_args( - chand->incoming_resolver_result); + grpc_resolver_result_get_addresses(chand->resolver_result); + lb_policy_args.additional_args = + grpc_resolver_result_get_lb_policy_args(chand->resolver_result); lb_policy_args.client_channel_factory = chand->client_channel_factory; lb_policy = grpc_lb_policy_create( exec_ctx, - grpc_resolver_result_get_lb_policy_name( - chand->incoming_resolver_result), + grpc_resolver_result_get_lb_policy_name(chand->resolver_result), &lb_policy_args); if (lb_policy != NULL) { GRPC_LB_POLICY_REF(lb_policy, "config_change"); @@ -200,11 +200,15 @@ static void on_resolver_result_changed(grpc_exec_ctx *exec_ctx, void *arg, state = grpc_lb_policy_check_connectivity(exec_ctx, lb_policy, &state_error); } - if (chand->current_resolver_result != NULL) { - grpc_resolver_result_unref(exec_ctx, chand->current_resolver_result); + const grpc_arg *channel_arg = grpc_channel_args_find( + lb_policy_args.additional_args, GRPC_ARG_SERVICE_CONFIG); + if (channel_arg != NULL) { + GPR_ASSERT(channel_arg->type == GRPC_ARG_POINTER); + method_config_table = grpc_method_config_table_ref( + (grpc_method_config_table *)channel_arg->value.pointer.p); } - chand->current_resolver_result = chand->incoming_resolver_result; - chand->incoming_resolver_result = NULL; + grpc_resolver_result_unref(exec_ctx, chand->resolver_result); + chand->resolver_result = NULL; } if (lb_policy != NULL) { @@ -215,6 +219,10 @@ static void on_resolver_result_changed(grpc_exec_ctx *exec_ctx, void *arg, gpr_mu_lock(&chand->mu); old_lb_policy = chand->lb_policy; chand->lb_policy = lb_policy; + if (chand->method_config_table != NULL) { + grpc_method_config_table_unref(chand->method_config_table); + } + chand->method_config_table = method_config_table; if (lb_policy != NULL) { grpc_exec_ctx_enqueue_list(exec_ctx, &chand->waiting_for_config_closures, NULL); @@ -238,8 +246,7 @@ static void on_resolver_result_changed(grpc_exec_ctx *exec_ctx, void *arg, watch_lb_policy(exec_ctx, chand, lb_policy, state); } GRPC_CHANNEL_STACK_REF(chand->owning_stack, "resolver"); - grpc_resolver_next(exec_ctx, chand->resolver, - &chand->incoming_resolver_result, + grpc_resolver_next(exec_ctx, chand->resolver, &chand->resolver_result, &chand->on_resolver_result_changed); gpr_mu_unlock(&chand->mu); } else { @@ -376,8 +383,8 @@ static void cc_destroy_channel_elem(grpc_exec_ctx *exec_ctx, chand->interested_parties); GRPC_LB_POLICY_UNREF(exec_ctx, chand->lb_policy, "channel"); } - if (chand->current_resolver_result != NULL) { - grpc_resolver_result_unref(exec_ctx, chand->current_resolver_result); + if (chand->method_config_table != NULL) { + grpc_method_config_table_unref(chand->method_config_table); } grpc_connectivity_state_destroy(exec_ctx, &chand->state_tracker); grpc_pollset_set_destroy(chand->interested_parties); @@ -512,11 +519,9 @@ static void subchannel_ready(grpc_exec_ctx *exec_ctx, void *arg, /* Get method config. */ // FIXME: need to actually use the config data! // FIXME: think about refcounting vs. atomicity here - grpc_method_config_table* table = grpc_resolver_result_get_method_configs( - chand->current_resolver_result); - if (table != NULL) { + if (chand->method_config_table != NULL) { calld->method_config = grpc_method_config_table_get_method_config( - table, calld->path); + chand->method_config_table, calld->path); } /* Create call on subchannel. */ grpc_subchannel_call *subchannel_call = NULL; @@ -626,8 +631,7 @@ static bool pick_subchannel(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, if (chand->resolver != NULL && !chand->started_resolving) { chand->started_resolving = true; GRPC_CHANNEL_STACK_REF(chand->owning_stack, "resolver"); - grpc_resolver_next(exec_ctx, chand->resolver, - &chand->incoming_resolver_result, + grpc_resolver_next(exec_ctx, chand->resolver, &chand->resolver_result, &chand->on_resolver_result_changed); } if (chand->resolver != NULL) { @@ -836,7 +840,7 @@ void grpc_client_channel_finish_initialization( chand->exit_idle_when_lb_policy_arrives) { chand->started_resolving = true; GRPC_CHANNEL_STACK_REF(chand->owning_stack, "resolver"); - grpc_resolver_next(exec_ctx, resolver, &chand->incoming_resolver_result, + grpc_resolver_next(exec_ctx, resolver, &chand->resolver_result, &chand->on_resolver_result_changed); } chand->client_channel_factory = client_channel_factory; @@ -858,8 +862,7 @@ grpc_connectivity_state grpc_client_channel_check_connectivity_state( if (!chand->started_resolving && chand->resolver != NULL) { GRPC_CHANNEL_STACK_REF(chand->owning_stack, "resolver"); chand->started_resolving = true; - grpc_resolver_next(exec_ctx, chand->resolver, - &chand->incoming_resolver_result, + grpc_resolver_next(exec_ctx, chand->resolver, &chand->resolver_result, &chand->on_resolver_result_changed); } } diff --git a/src/core/ext/client_config/method_config.c b/src/core/ext/client_config/method_config.c index e3589153fb6..989f7769677 100644 --- a/src/core/ext/client_config/method_config.c +++ b/src/core/ext/client_config/method_config.c @@ -33,9 +33,11 @@ #include +#include #include #include #include +#include #include "src/core/lib/transport/metadata.h" @@ -212,3 +214,72 @@ grpc_method_config* grpc_method_config_table_get_method_config( } return grpc_method_config_ref(method_config); } + +static void* copy_arg(void* p) { + return grpc_method_config_table_ref(p); +} + +static void destroy_arg(void* p) { + grpc_method_config_table_unref(p); +} + +static int cmp_arg(void* p1, void* p2) { + grpc_method_config_table* t1 = p1; + grpc_method_config_table* t2 = p2; + for (size_t i = 0; i < GPR_ARRAY_SIZE(t1->entries); ++i) { + grpc_method_config_table_entry* e1 = &t1->entries[i]; + grpc_method_config_table_entry* e2 = &t2->entries[i]; + // Compare paths by hash value. + if (e1->path->hash < e2->path->hash) return -1; + if (e1->path->hash > e2->path->hash) return 1; + // Compare wait_for_ready. + const bool wait_for_ready1 = + e1->method_config->wait_for_ready == NULL + ? false : *e1->method_config->wait_for_ready; + const bool wait_for_ready2 = + e2->method_config->wait_for_ready == NULL + ? false : *e2->method_config->wait_for_ready; + if (wait_for_ready1 < wait_for_ready2) return -1; + if (wait_for_ready1 > wait_for_ready2) return 1; + // Compare timeout. + const gpr_timespec timeout1 = + e1->method_config->timeout == NULL + ? gpr_inf_past(GPR_CLOCK_MONOTONIC) : *e1->method_config->timeout; + const gpr_timespec timeout2 = + e2->method_config->timeout == NULL + ? gpr_inf_past(GPR_CLOCK_MONOTONIC) : *e2->method_config->timeout; + const int timeout_result = gpr_time_cmp(timeout1, timeout2); + if (timeout_result != 0) return timeout_result; + // Compare max_request_message_bytes. + const int32_t max_request_message_bytes1 = + e1->method_config->max_request_message_bytes == NULL + ? -1 : *e1->method_config->max_request_message_bytes; + const int32_t max_request_message_bytes2 = + e2->method_config->max_request_message_bytes == NULL + ? -1 : *e2->method_config->max_request_message_bytes; + if (max_request_message_bytes1 < max_request_message_bytes2) return -1; + if (max_request_message_bytes1 > max_request_message_bytes2) return 1; + // Compare max_response_message_bytes. + const int32_t max_response_message_bytes1 = + e1->method_config->max_response_message_bytes == NULL + ? -1 : *e1->method_config->max_response_message_bytes; + const int32_t max_response_message_bytes2 = + e2->method_config->max_response_message_bytes == NULL + ? -1 : *e2->method_config->max_response_message_bytes; + if (max_response_message_bytes1 < max_response_message_bytes2) return -1; + if (max_response_message_bytes1 > max_response_message_bytes2) return 1; + } + return 0; +} + +static grpc_arg_pointer_vtable arg_vtable = {copy_arg, destroy_arg, cmp_arg}; + +grpc_arg grpc_method_config_table_create_channel_arg( + grpc_method_config_table* table) { + grpc_arg arg; + arg.type = GRPC_ARG_POINTER; + arg.key = GRPC_ARG_SERVICE_CONFIG; + arg.value.pointer.p = grpc_method_config_table_ref(table); + arg.value.pointer.vtable = &arg_vtable; + return arg; +} diff --git a/src/core/ext/client_config/method_config.h b/src/core/ext/client_config/method_config.h index 9490e296b27..2be0cd1006b 100644 --- a/src/core/ext/client_config/method_config.h +++ b/src/core/ext/client_config/method_config.h @@ -35,6 +35,7 @@ #include #include +#include #include "src/core/lib/transport/metadata.h" @@ -82,4 +83,8 @@ void grpc_method_config_table_add_method_config( grpc_method_config* grpc_method_config_table_get_method_config( grpc_method_config_table* table, grpc_mdstr* path); +/// Returns a channel arg containing \a table. +grpc_arg grpc_method_config_table_create_channel_arg( + grpc_method_config_table* table); + #endif /* GRPC_CORE_EXT_CLIENT_CONFIG_METHOD_CONFIG_H */ diff --git a/src/core/ext/client_config/resolver_result.c b/src/core/ext/client_config/resolver_result.c index 5c5ffb2635f..16d124d2055 100644 --- a/src/core/ext/client_config/resolver_result.c +++ b/src/core/ext/client_config/resolver_result.c @@ -49,13 +49,11 @@ struct grpc_resolver_result { grpc_lb_addresses* addresses; char* lb_policy_name; grpc_channel_args* lb_policy_args; - grpc_method_config_table* method_configs; }; grpc_resolver_result* grpc_resolver_result_create( const char* server_name, grpc_lb_addresses* addresses, - const char* lb_policy_name, grpc_channel_args* lb_policy_args, - grpc_method_config_table* method_configs) { + const char* lb_policy_name, grpc_channel_args* lb_policy_args) { grpc_resolver_result* result = gpr_malloc(sizeof(*result)); memset(result, 0, sizeof(*result)); gpr_ref_init(&result->refs, 1); @@ -63,7 +61,6 @@ grpc_resolver_result* grpc_resolver_result_create( result->addresses = addresses; result->lb_policy_name = gpr_strdup(lb_policy_name); result->lb_policy_args = lb_policy_args; - result->method_configs = grpc_method_config_table_ref(method_configs); return result; } @@ -78,7 +75,6 @@ void grpc_resolver_result_unref(grpc_exec_ctx* exec_ctx, grpc_lb_addresses_destroy(result->addresses, NULL /* user_data_destroy */); gpr_free(result->lb_policy_name); grpc_channel_args_destroy(result->lb_policy_args); - grpc_method_config_table_unref(result->method_configs); gpr_free(result); } } @@ -101,8 +97,3 @@ grpc_channel_args* grpc_resolver_result_get_lb_policy_args( grpc_resolver_result* result) { return result->lb_policy_args; } - -grpc_method_config_table* grpc_resolver_result_get_method_configs( - grpc_resolver_result* result) { - return result->method_configs; -} diff --git a/src/core/ext/client_config/resolver_result.h b/src/core/ext/client_config/resolver_result.h index e6127f1d6d4..707c8c2cf5c 100644 --- a/src/core/ext/client_config/resolver_result.h +++ b/src/core/ext/client_config/resolver_result.h @@ -33,7 +33,6 @@ #define GRPC_CORE_EXT_CLIENT_CONFIG_RESOLVER_RESULT_H #include "src/core/ext/client_config/lb_policy_factory.h" -#include "src/core/ext/client_config/method_config.h" #include "src/core/lib/iomgr/resolve_address.h" // TODO(roth, ctiller): In the long term, we are considering replacing @@ -52,8 +51,7 @@ typedef struct grpc_resolver_result grpc_resolver_result; /// Takes ownership of \a addresses, \a lb_policy_args. grpc_resolver_result* grpc_resolver_result_create( const char* server_name, grpc_lb_addresses* addresses, - const char* lb_policy_name, grpc_channel_args* lb_policy_args, - grpc_method_config_table* method_configs); + const char* lb_policy_name, grpc_channel_args* lb_policy_args); void grpc_resolver_result_ref(grpc_resolver_result* result); void grpc_resolver_result_unref(grpc_exec_ctx* exec_ctx, @@ -67,7 +65,5 @@ const char* grpc_resolver_result_get_lb_policy_name( grpc_resolver_result* result); grpc_channel_args* grpc_resolver_result_get_lb_policy_args( grpc_resolver_result* result); -grpc_method_config_table* grpc_resolver_result_get_method_configs( - grpc_resolver_result* result); #endif /* GRPC_CORE_EXT_CLIENT_CONFIG_RESOLVER_RESULT_H */ diff --git a/src/core/ext/lb_policy/grpclb/grpclb.c b/src/core/ext/lb_policy/grpclb/grpclb.c index 8105c4415d8..de3438be810 100644 --- a/src/core/ext/lb_policy/grpclb/grpclb.c +++ b/src/core/ext/lb_policy/grpclb/grpclb.c @@ -112,6 +112,7 @@ #include "src/core/ext/client_config/parse_address.h" #include "src/core/ext/lb_policy/grpclb/grpclb.h" #include "src/core/ext/lb_policy/grpclb/load_balancer_api.h" +#include "src/core/lib/channel/channel_args.h" #include "src/core/lib/iomgr/sockaddr.h" #include "src/core/lib/iomgr/sockaddr_utils.h" #include "src/core/lib/support/string.h" @@ -285,6 +286,7 @@ typedef struct glb_lb_policy { const char *server_name; grpc_client_channel_factory *cc_factory; + grpc_channel_args *args; /** for communicating with the LB server */ grpc_channel *lb_channel; @@ -442,6 +444,7 @@ static grpc_lb_policy *create_rr(grpc_exec_ctx *exec_ctx, args.server_name = glb_policy->server_name; args.client_channel_factory = glb_policy->cc_factory; args.addresses = process_serverlist(serverlist); + args.additional_args = glb_policy->args; grpc_lb_policy *rr = grpc_lb_policy_create(exec_ctx, "round_robin", &args); @@ -567,6 +570,7 @@ static grpc_lb_policy *glb_create(grpc_exec_ctx *exec_ctx, * Create a client channel over them to communicate with a LB service */ glb_policy->server_name = gpr_strdup(args->server_name); glb_policy->cc_factory = args->client_channel_factory; + glb_policy->args = grpc_channel_args_copy(args->additional_args); GPR_ASSERT(glb_policy->cc_factory != NULL); /* construct a target from the addresses in args, given in the form @@ -633,6 +637,7 @@ static void glb_destroy(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { GPR_ASSERT(glb_policy->pending_picks == NULL); GPR_ASSERT(glb_policy->pending_pings == NULL); gpr_free((void *)glb_policy->server_name); + grpc_channel_args_destroy(glb_policy->args); grpc_channel_destroy(glb_policy->lb_channel); glb_policy->lb_channel = NULL; grpc_connectivity_state_destroy(exec_ctx, &glb_policy->state_tracker); diff --git a/src/core/ext/lb_policy/pick_first/pick_first.c b/src/core/ext/lb_policy/pick_first/pick_first.c index 466a0fdede8..10030ef18bf 100644 --- a/src/core/ext/lb_policy/pick_first/pick_first.c +++ b/src/core/ext/lb_policy/pick_first/pick_first.c @@ -470,6 +470,7 @@ static grpc_lb_policy *create_pick_first(grpc_exec_ctx *exec_ctx, sc_args.addr = (struct sockaddr *)(&args->addresses->addresses[i].address.addr); sc_args.addr_len = args->addresses->addresses[i].address.len; + sc_args.args = args->additional_args; grpc_subchannel *subchannel = grpc_client_channel_factory_create_subchannel( exec_ctx, args->client_channel_factory, &sc_args); diff --git a/src/core/ext/lb_policy/round_robin/round_robin.c b/src/core/ext/lb_policy/round_robin/round_robin.c index 037f180a9e7..b6cfe8994d1 100644 --- a/src/core/ext/lb_policy/round_robin/round_robin.c +++ b/src/core/ext/lb_policy/round_robin/round_robin.c @@ -633,6 +633,7 @@ static grpc_lb_policy *round_robin_create(grpc_exec_ctx *exec_ctx, sc_args.addr = (struct sockaddr *)(&args->addresses->addresses[i].address.addr); sc_args.addr_len = args->addresses->addresses[i].address.len; + sc_args.args = args->additional_args; grpc_subchannel *subchannel = grpc_client_channel_factory_create_subchannel( exec_ctx, args->client_channel_factory, &sc_args); diff --git a/src/core/ext/resolver/dns/native/dns_resolver.c b/src/core/ext/resolver/dns/native/dns_resolver.c index 879e26f7d94..e8ac1b12ae8 100644 --- a/src/core/ext/resolver/dns/native/dns_resolver.c +++ b/src/core/ext/resolver/dns/native/dns_resolver.c @@ -181,7 +181,7 @@ static void dns_on_resolved(grpc_exec_ctx *exec_ctx, void *arg, } grpc_resolved_addresses_destroy(r->addresses); result = grpc_resolver_result_create(r->target_name, addresses, - r->lb_policy_name, NULL, NULL); + r->lb_policy_name, NULL); } else { gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC); gpr_timespec next_try = gpr_backoff_step(&r->backoff_state, now); diff --git a/src/core/ext/resolver/sockaddr/sockaddr_resolver.c b/src/core/ext/resolver/sockaddr/sockaddr_resolver.c index 61be1b3c256..74d2015e5c2 100644 --- a/src/core/ext/resolver/sockaddr/sockaddr_resolver.c +++ b/src/core/ext/resolver/sockaddr/sockaddr_resolver.c @@ -122,7 +122,7 @@ static void sockaddr_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx, r->published = true; *r->target_result = grpc_resolver_result_create( "", grpc_lb_addresses_copy(r->addresses, NULL /* user_data_copy */), - r->lb_policy_name, NULL, NULL); + r->lb_policy_name, NULL); grpc_exec_ctx_sched(exec_ctx, r->next_completion, GRPC_ERROR_NONE, NULL); r->next_completion = NULL; } diff --git a/src/core/lib/channel/channel_args.c b/src/core/lib/channel/channel_args.c index 3a56b1ff205..bab6fcd9fa2 100644 --- a/src/core/lib/channel/channel_args.c +++ b/src/core/lib/channel/channel_args.c @@ -272,6 +272,16 @@ int grpc_channel_args_compare(const grpc_channel_args *a, return 0; } +const grpc_arg *grpc_channel_args_find(const grpc_channel_args *args, + const char *name) { + if (args != NULL) { + for (size_t i = 0; i < args->num_args; ++i) { + if (args->args[i].key == name) return &args->args[i]; + } + } + return NULL; +} + int grpc_channel_arg_get_integer(grpc_arg *arg, grpc_integer_options options) { if (arg->type != GRPC_ARG_INTEGER) { gpr_log(GPR_ERROR, "%s ignored: it must be an integer", arg->key); diff --git a/src/core/lib/channel/channel_args.h b/src/core/lib/channel/channel_args.h index 586a296d1f6..38fb4c55d46 100644 --- a/src/core/lib/channel/channel_args.h +++ b/src/core/lib/channel/channel_args.h @@ -89,6 +89,12 @@ uint32_t grpc_channel_args_compression_algorithm_get_states( int grpc_channel_args_compare(const grpc_channel_args *a, const grpc_channel_args *b); +/** Returns the value of argument \a name from \a args, or NULL if not found. + Note: \a name is matched using pointer equality, so it must be the + same instance of the string used to create the grpc_arg key. */ +const grpc_arg *grpc_channel_args_find(const grpc_channel_args *args, + const char *name); + typedef struct grpc_integer_options { int default_value; // Return this if value is outside of expected bounds. int min_value; From aa850a7b48ac78f9b86e036b448519ec579c440b Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Mon, 26 Sep 2016 13:38:02 -0700 Subject: [PATCH 08/48] Pass path into init_call_elem() for use in looking up method config. --- src/core/ext/client_config/client_channel.c | 52 ++++++++------------- src/core/ext/client_config/subchannel.c | 4 +- src/core/ext/client_config/subchannel.h | 3 +- src/core/lib/channel/channel_stack.c | 3 +- src/core/lib/channel/channel_stack.h | 3 +- src/core/lib/channel/deadline_filter.c | 20 ++++++-- src/core/lib/channel/deadline_filter.h | 5 +- src/core/lib/surface/call.c | 8 +++- 8 files changed, 56 insertions(+), 42 deletions(-) diff --git a/src/core/ext/client_config/client_channel.c b/src/core/ext/client_config/client_channel.c index 87e3a1a63a6..e61d2534806 100644 --- a/src/core/ext/client_config/client_channel.c +++ b/src/core/ext/client_config/client_channel.c @@ -421,6 +421,9 @@ typedef struct client_channel_call_data { grpc_deadline_state deadline_state; gpr_timespec deadline; + // Request path. + grpc_mdstr *path; + grpc_error *cancel_error; /** either 0 for no call, 1 for cancelled, or a pointer to a @@ -433,9 +436,6 @@ typedef struct client_channel_call_data { grpc_connected_subchannel *connected_subchannel; grpc_polling_entity *pollent; - grpc_mdstr *path; - grpc_method_config *method_config; - grpc_transport_stream_op **waiting_ops; size_t waiting_ops_count; size_t waiting_ops_capacity; @@ -511,9 +511,7 @@ static void retry_waiting_locked(grpc_exec_ctx *exec_ctx, call_data *calld) { static void subchannel_ready(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { - grpc_call_element *elem = arg; - call_data *calld = elem->call_data; - channel_data *chand = elem->channel_data; + call_data *calld = arg; gpr_mu_lock(&calld->mu); GPR_ASSERT(calld->creation_phase == GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL); @@ -528,18 +526,11 @@ static void subchannel_ready(grpc_exec_ctx *exec_ctx, void *arg, GRPC_ERROR_CREATE_REFERENCING( "Cancelled before creating subchannel", &error, 1)); } else { - /* Get method config. */ -// FIXME: need to actually use the config data! -// FIXME: think about refcounting vs. atomicity here - if (chand->method_config_table != NULL) { - calld->method_config = grpc_method_config_table_get_method_config( - chand->method_config_table, calld->path); - } /* Create call on subchannel. */ grpc_subchannel_call *subchannel_call = NULL; grpc_error *new_error = grpc_connected_subchannel_create_call( - exec_ctx, calld->connected_subchannel, calld->pollent, calld->deadline, - &subchannel_call); + exec_ctx, calld->connected_subchannel, calld->pollent, calld->path, + calld->deadline, &subchannel_call); if (new_error != GRPC_ERROR_NONE) { new_error = grpc_error_add_child(new_error, error); subchannel_call = CANCELLED_CALL; @@ -745,15 +736,8 @@ retry: if (calld->creation_phase == GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING && calld->connected_subchannel == NULL && op->send_initial_metadata != NULL) { - for (grpc_linked_mdelem *mdelem = op->send_initial_metadata->list.head; - mdelem != NULL; mdelem = mdelem->next) { - if (mdelem->md->key == GRPC_MDSTR_PATH) { - calld->path = GRPC_MDSTR_REF(mdelem->md->value); - break; - } - } calld->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL; - grpc_closure_init(&calld->next_step, subchannel_ready, elem); + grpc_closure_init(&calld->next_step, subchannel_ready, calld); GRPC_CALL_STACK_REF(calld->owning_call, "pick_subchannel"); if (pick_subchannel(exec_ctx, elem, op->send_initial_metadata, op->send_initial_metadata_flags, @@ -768,8 +752,8 @@ retry: calld->connected_subchannel != NULL) { grpc_subchannel_call *subchannel_call = NULL; grpc_error *error = grpc_connected_subchannel_create_call( - exec_ctx, calld->connected_subchannel, calld->pollent, calld->deadline, - &subchannel_call); + exec_ctx, calld->connected_subchannel, calld->pollent, calld->path, + calld->deadline, &subchannel_call); if (error != GRPC_ERROR_NONE) { subchannel_call = CANCELLED_CALL; fail_locked(exec_ctx, calld, GRPC_ERROR_REF(error)); @@ -790,15 +774,22 @@ retry: static grpc_error *cc_init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, grpc_call_element_args *args) { + channel_data *chand = elem->channel_data; call_data *calld = elem->call_data; - grpc_deadline_state_init(exec_ctx, elem, args); + gpr_mu_lock(&chand->mu); + grpc_method_config_table *method_config_table = + chand->method_config_table == NULL + ? NULL + : grpc_method_config_table_ref(chand->method_config_table); + gpr_mu_unlock(&chand->mu); + grpc_deadline_state_init(exec_ctx, elem, args, method_config_table); + grpc_method_config_table_unref(chand->method_config_table); calld->deadline = args->deadline; + calld->path = GRPC_MDSTR_REF(args->path); calld->cancel_error = GRPC_ERROR_NONE; gpr_atm_rel_store(&calld->subchannel_call, 0); gpr_mu_init(&calld->mu); calld->connected_subchannel = NULL; - calld->path = NULL; - calld->method_config = NULL; calld->waiting_ops = NULL; calld->waiting_ops_count = 0; calld->waiting_ops_capacity = 0; @@ -815,11 +806,8 @@ static void cc_destroy_call_elem(grpc_exec_ctx *exec_ctx, void *and_free_memory) { call_data *calld = elem->call_data; grpc_deadline_state_destroy(exec_ctx, elem); + GRPC_MDSTR_UNREF(calld->path); GRPC_ERROR_UNREF(calld->cancel_error); - -// FIXME: remove - if (calld->path != NULL) GRPC_MDSTR_UNREF(calld->path); - grpc_subchannel_call *call = GET_CALL(calld); if (call != NULL && call != CANCELLED_CALL) { GRPC_SUBCHANNEL_CALL_UNREF(exec_ctx, call, "client_channel_destroy_call"); diff --git a/src/core/ext/client_config/subchannel.c b/src/core/ext/client_config/subchannel.c index f2b860807f3..6674dbbe68f 100644 --- a/src/core/ext/client_config/subchannel.c +++ b/src/core/ext/client_config/subchannel.c @@ -700,7 +700,7 @@ grpc_connected_subchannel *grpc_subchannel_get_connected_subchannel( grpc_error *grpc_connected_subchannel_create_call( grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *con, - grpc_polling_entity *pollent, gpr_timespec deadline, + grpc_polling_entity *pollent, grpc_mdstr *path, gpr_timespec deadline, grpc_subchannel_call **call) { grpc_channel_stack *chanstk = CHANNEL_STACK_FROM_CONNECTION(con); *call = gpr_malloc(sizeof(grpc_subchannel_call) + chanstk->call_stack_size); @@ -708,7 +708,7 @@ grpc_error *grpc_connected_subchannel_create_call( (*call)->connection = con; // Ref is added below. grpc_error *error = grpc_call_stack_init(exec_ctx, chanstk, 1, subchannel_call_destroy, *call, - NULL, NULL, deadline, callstk); + NULL, NULL, path, deadline, callstk); if (error != GRPC_ERROR_NONE) { const char *error_string = grpc_error_string(error); gpr_log(GPR_ERROR, "error: %s", error_string); diff --git a/src/core/ext/client_config/subchannel.h b/src/core/ext/client_config/subchannel.h index 33306210712..f8de26dfd51 100644 --- a/src/core/ext/client_config/subchannel.h +++ b/src/core/ext/client_config/subchannel.h @@ -38,6 +38,7 @@ #include "src/core/lib/channel/channel_stack.h" #include "src/core/lib/iomgr/polling_entity.h" #include "src/core/lib/transport/connectivity_state.h" +#include "src/core/lib/transport/metadata.h" /** A (sub-)channel that knows how to connect to exactly one target address. Provides a target for load balancing. */ @@ -110,7 +111,7 @@ void grpc_subchannel_call_unref(grpc_exec_ctx *exec_ctx, /** construct a subchannel call */ grpc_error *grpc_connected_subchannel_create_call( grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *connected_subchannel, - grpc_polling_entity *pollent, gpr_timespec deadline, + grpc_polling_entity *pollent, grpc_mdstr *path, gpr_timespec deadline, grpc_subchannel_call **subchannel_call); /** process a transport level op */ diff --git a/src/core/lib/channel/channel_stack.c b/src/core/lib/channel/channel_stack.c index 57d34d9e9ab..205496f2f26 100644 --- a/src/core/lib/channel/channel_stack.c +++ b/src/core/lib/channel/channel_stack.c @@ -162,7 +162,7 @@ grpc_error *grpc_call_stack_init( grpc_exec_ctx *exec_ctx, grpc_channel_stack *channel_stack, int initial_refs, grpc_iomgr_cb_func destroy, void *destroy_arg, grpc_call_context_element *context, const void *transport_server_data, - gpr_timespec deadline, grpc_call_stack *call_stack) { + grpc_mdstr *path, gpr_timespec deadline, grpc_call_stack *call_stack) { grpc_channel_element *channel_elems = CHANNEL_ELEMS_FROM_STACK(channel_stack); grpc_call_element_args args; size_t count = channel_stack->count; @@ -183,6 +183,7 @@ grpc_error *grpc_call_stack_init( args.call_stack = call_stack; args.server_transport_data = transport_server_data; args.context = context; + args.path = path; args.deadline = deadline; call_elems[i].filter = channel_elems[i].filter; call_elems[i].channel_data = channel_elems[i].channel_data; diff --git a/src/core/lib/channel/channel_stack.h b/src/core/lib/channel/channel_stack.h index 1cfe2885d81..5b46cd32a3a 100644 --- a/src/core/lib/channel/channel_stack.h +++ b/src/core/lib/channel/channel_stack.h @@ -74,6 +74,7 @@ typedef struct { grpc_call_stack *call_stack; const void *server_transport_data; grpc_call_context_element *context; + grpc_mdstr *path; gpr_timespec deadline; } grpc_call_element_args; @@ -225,7 +226,7 @@ grpc_error *grpc_call_stack_init( grpc_exec_ctx *exec_ctx, grpc_channel_stack *channel_stack, int initial_refs, grpc_iomgr_cb_func destroy, void *destroy_arg, grpc_call_context_element *context, const void *transport_server_data, - gpr_timespec deadline, grpc_call_stack *call_stack); + grpc_mdstr *path, gpr_timespec deadline, grpc_call_stack *call_stack); /* Set a pollset or a pollset_set for a call stack: must occur before the first * op is started */ void grpc_call_stack_set_pollset_or_pollset_set(grpc_exec_ctx *exec_ctx, diff --git a/src/core/lib/channel/deadline_filter.c b/src/core/lib/channel/deadline_filter.c index 079b98a2f85..89dc8dd6e8c 100644 --- a/src/core/lib/channel/deadline_filter.c +++ b/src/core/lib/channel/deadline_filter.c @@ -123,15 +123,28 @@ static void start_timer_after_init(grpc_exec_ctx* exec_ctx, void* arg, } void grpc_deadline_state_init(grpc_exec_ctx* exec_ctx, grpc_call_element* elem, - grpc_call_element_args* args) { + grpc_call_element_args* args, + grpc_method_config_table* method_config_table) { grpc_deadline_state* deadline_state = elem->call_data; memset(deadline_state, 0, sizeof(*deadline_state)); deadline_state->call_stack = args->call_stack; gpr_mu_init(&deadline_state->timer_mu); // Deadline will always be infinite on servers, so the timer will only be // set on clients with a finite deadline. - const gpr_timespec deadline = + gpr_timespec deadline = gpr_convert_clock_type(args->deadline, GPR_CLOCK_MONOTONIC); + if (method_config_table != NULL) { + grpc_method_config* method_config = + grpc_method_config_table_get_method_config(method_config_table, + args->path); + if (method_config != NULL) { + gpr_timespec* per_method_deadline = + grpc_method_config_get_timeout(method_config); + if (per_method_deadline != NULL) { + deadline = gpr_time_min(deadline, *per_method_deadline); + } + } + } if (gpr_time_cmp(deadline, gpr_inf_future(GPR_CLOCK_MONOTONIC)) != 0) { // When the deadline passes, we indicate the failure by sending down // an op with cancel_error set. However, we can't send down any ops @@ -209,7 +222,8 @@ static grpc_error* init_call_elem(grpc_exec_ctx* exec_ctx, grpc_call_element_args* args) { // Note: size of call data is different between client and server. memset(elem->call_data, 0, elem->filter->sizeof_call_data); - grpc_deadline_state_init(exec_ctx, elem, args); + grpc_deadline_state_init(exec_ctx, elem, args, + NULL /* method_config_table */); return GRPC_ERROR_NONE; } diff --git a/src/core/lib/channel/deadline_filter.h b/src/core/lib/channel/deadline_filter.h index 685df877617..2fcee0b9ef0 100644 --- a/src/core/lib/channel/deadline_filter.h +++ b/src/core/lib/channel/deadline_filter.h @@ -35,6 +35,8 @@ #include "src/core/lib/channel/channel_stack.h" #include "src/core/lib/iomgr/timer.h" +#include "src/core/ext/client_config/method_config.h" + // State used for filters that enforce call deadlines. // Must be the first field in the filter's call_data. typedef struct grpc_deadline_state { @@ -63,7 +65,8 @@ typedef struct grpc_deadline_state { // caller's responsibility to chain to the next filter if necessary // after the function returns. void grpc_deadline_state_init(grpc_exec_ctx* exec_ctx, grpc_call_element* elem, - grpc_call_element_args* args); + grpc_call_element_args* args, + grpc_method_config_table* method_config_table); void grpc_deadline_state_destroy(grpc_exec_ctx* exec_ctx, grpc_call_element* elem); void grpc_deadline_state_client_start_transport_stream_op( diff --git a/src/core/lib/surface/call.c b/src/core/lib/surface/call.c index 5690bcab1e4..0af72547e37 100644 --- a/src/core/lib/surface/call.c +++ b/src/core/lib/surface/call.c @@ -242,10 +242,14 @@ grpc_call *grpc_call_create( /* Always support no compression */ GPR_BITSET(&call->encodings_accepted_by_peer, GRPC_COMPRESS_NONE); call->is_client = server_transport_data == NULL; + grpc_mdstr *path = NULL; if (call->is_client) { GPR_ASSERT(add_initial_metadata_count < MAX_SEND_EXTRA_METADATA_COUNT); for (i = 0; i < add_initial_metadata_count; i++) { call->send_extra_metadata[i].md = add_initial_metadata[i]; + if (add_initial_metadata[i]->key == GRPC_MDSTR_PATH) { + path = GRPC_MDSTR_REF(add_initial_metadata[i]->value); + } } call->send_extra_metadata_count = (int)add_initial_metadata_count; } else { @@ -307,7 +311,7 @@ grpc_call *grpc_call_create( /* initial refcount dropped by grpc_call_destroy */ grpc_error *error = grpc_call_stack_init( &exec_ctx, channel_stack, 1, destroy_call, call, call->context, - server_transport_data, send_deadline, CALL_STACK_FROM_CALL(call)); + server_transport_data, path, send_deadline, CALL_STACK_FROM_CALL(call)); if (error != GRPC_ERROR_NONE) { grpc_status_code status; const char *error_str; @@ -332,6 +336,8 @@ grpc_call *grpc_call_create( &exec_ctx, CALL_STACK_FROM_CALL(call), &call->pollent); } + if (path != NULL) GRPC_MDSTR_UNREF(path); + grpc_exec_ctx_finish(&exec_ctx); GPR_TIMER_END("grpc_call_create", 0); return call; From 6600645135597fec4feaae81ca64fb02694d5f60 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Tue, 27 Sep 2016 10:13:56 -0700 Subject: [PATCH 09/48] Refactor hash table code into its own module and use it for method_config as well as method_config_table. --- BUILD | 12 + CMakeLists.txt | 5 + Makefile | 6 + binding.gyp | 1 + build.yaml | 2 + config.m4 | 1 + gRPC-Core.podspec | 3 + grpc.gemspec | 2 + package.xml | 2 + src/core/ext/client_config/method_config.c | 284 +++++++++--------- src/core/ext/client_config/method_config.h | 29 +- src/core/lib/transport/hashtable.c | 139 +++++++++ src/core/lib/transport/hashtable.h | 82 +++++ src/python/grpcio/grpc_core_dependencies.py | 1 + tools/doxygen/Doxyfile.c++.internal | 2 + tools/doxygen/Doxyfile.core.internal | 2 + tools/run_tests/sources_and_headers.json | 3 + vsprojects/vcxproj/grpc++/grpc++.vcxproj | 3 + .../vcxproj/grpc++/grpc++.vcxproj.filters | 6 + .../grpc++_unsecure/grpc++_unsecure.vcxproj | 3 + .../grpc++_unsecure.vcxproj.filters | 6 + vsprojects/vcxproj/grpc/grpc.vcxproj | 3 + vsprojects/vcxproj/grpc/grpc.vcxproj.filters | 6 + .../grpc_test_util/grpc_test_util.vcxproj | 3 + .../grpc_test_util.vcxproj.filters | 6 + .../grpc_unsecure/grpc_unsecure.vcxproj | 3 + .../grpc_unsecure.vcxproj.filters | 6 + 27 files changed, 470 insertions(+), 151 deletions(-) create mode 100644 src/core/lib/transport/hashtable.c create mode 100644 src/core/lib/transport/hashtable.h diff --git a/BUILD b/BUILD index d542561ec85..46adf28f29f 100644 --- a/BUILD +++ b/BUILD @@ -239,6 +239,7 @@ cc_library( "src/core/lib/surface/server.h", "src/core/lib/transport/byte_stream.h", "src/core/lib/transport/connectivity_state.h", + "src/core/lib/transport/hashtable.h", "src/core/lib/transport/metadata.h", "src/core/lib/transport/metadata_batch.h", "src/core/lib/transport/static_metadata.h", @@ -410,6 +411,7 @@ cc_library( "src/core/lib/surface/version.c", "src/core/lib/transport/byte_stream.c", "src/core/lib/transport/connectivity_state.c", + "src/core/lib/transport/hashtable.c", "src/core/lib/transport/metadata.c", "src/core/lib/transport/metadata_batch.c", "src/core/lib/transport/static_metadata.c", @@ -642,6 +644,7 @@ cc_library( "src/core/lib/surface/server.h", "src/core/lib/transport/byte_stream.h", "src/core/lib/transport/connectivity_state.h", + "src/core/lib/transport/hashtable.h", "src/core/lib/transport/metadata.h", "src/core/lib/transport/metadata_batch.h", "src/core/lib/transport/static_metadata.h", @@ -798,6 +801,7 @@ cc_library( "src/core/lib/surface/version.c", "src/core/lib/transport/byte_stream.c", "src/core/lib/transport/connectivity_state.c", + "src/core/lib/transport/hashtable.c", "src/core/lib/transport/metadata.c", "src/core/lib/transport/metadata_batch.c", "src/core/lib/transport/static_metadata.c", @@ -1000,6 +1004,7 @@ cc_library( "src/core/lib/surface/server.h", "src/core/lib/transport/byte_stream.h", "src/core/lib/transport/connectivity_state.h", + "src/core/lib/transport/hashtable.h", "src/core/lib/transport/metadata.h", "src/core/lib/transport/metadata_batch.h", "src/core/lib/transport/static_metadata.h", @@ -1148,6 +1153,7 @@ cc_library( "src/core/lib/surface/version.c", "src/core/lib/transport/byte_stream.c", "src/core/lib/transport/connectivity_state.c", + "src/core/lib/transport/hashtable.c", "src/core/lib/transport/metadata.c", "src/core/lib/transport/metadata_batch.c", "src/core/lib/transport/static_metadata.c", @@ -1355,6 +1361,7 @@ cc_library( "src/core/lib/surface/server.h", "src/core/lib/transport/byte_stream.h", "src/core/lib/transport/connectivity_state.h", + "src/core/lib/transport/hashtable.h", "src/core/lib/transport/metadata.h", "src/core/lib/transport/metadata_batch.h", "src/core/lib/transport/static_metadata.h", @@ -1480,6 +1487,7 @@ cc_library( "src/core/lib/surface/version.c", "src/core/lib/transport/byte_stream.c", "src/core/lib/transport/connectivity_state.c", + "src/core/lib/transport/hashtable.c", "src/core/lib/transport/metadata.c", "src/core/lib/transport/metadata_batch.c", "src/core/lib/transport/static_metadata.c", @@ -1765,6 +1773,7 @@ cc_library( "src/core/lib/surface/server.h", "src/core/lib/transport/byte_stream.h", "src/core/lib/transport/connectivity_state.h", + "src/core/lib/transport/hashtable.h", "src/core/lib/transport/metadata.h", "src/core/lib/transport/metadata_batch.h", "src/core/lib/transport/static_metadata.h", @@ -1885,6 +1894,7 @@ cc_library( "src/core/lib/surface/version.c", "src/core/lib/transport/byte_stream.c", "src/core/lib/transport/connectivity_state.c", + "src/core/lib/transport/hashtable.c", "src/core/lib/transport/metadata.c", "src/core/lib/transport/metadata_batch.c", "src/core/lib/transport/static_metadata.c", @@ -2274,6 +2284,7 @@ objc_library( "src/core/lib/surface/version.c", "src/core/lib/transport/byte_stream.c", "src/core/lib/transport/connectivity_state.c", + "src/core/lib/transport/hashtable.c", "src/core/lib/transport/metadata.c", "src/core/lib/transport/metadata_batch.c", "src/core/lib/transport/static_metadata.c", @@ -2485,6 +2496,7 @@ objc_library( "src/core/lib/surface/server.h", "src/core/lib/transport/byte_stream.h", "src/core/lib/transport/connectivity_state.h", + "src/core/lib/transport/hashtable.h", "src/core/lib/transport/metadata.h", "src/core/lib/transport/metadata_batch.h", "src/core/lib/transport/static_metadata.h", diff --git a/CMakeLists.txt b/CMakeLists.txt index 65a94bb9950..39ea8906bfe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -376,6 +376,7 @@ add_library(grpc src/core/lib/surface/version.c src/core/lib/transport/byte_stream.c src/core/lib/transport/connectivity_state.c + src/core/lib/transport/hashtable.c src/core/lib/transport/metadata.c src/core/lib/transport/metadata_batch.c src/core/lib/transport/static_metadata.c @@ -636,6 +637,7 @@ add_library(grpc_cronet src/core/lib/surface/version.c src/core/lib/transport/byte_stream.c src/core/lib/transport/connectivity_state.c + src/core/lib/transport/hashtable.c src/core/lib/transport/metadata.c src/core/lib/transport/metadata_batch.c src/core/lib/transport/static_metadata.c @@ -868,6 +870,7 @@ add_library(grpc_unsecure src/core/lib/surface/version.c src/core/lib/transport/byte_stream.c src/core/lib/transport/connectivity_state.c + src/core/lib/transport/hashtable.c src/core/lib/transport/metadata.c src/core/lib/transport/metadata_batch.c src/core/lib/transport/static_metadata.c @@ -1127,6 +1130,7 @@ add_library(grpc++ src/core/lib/surface/version.c src/core/lib/transport/byte_stream.c src/core/lib/transport/connectivity_state.c + src/core/lib/transport/hashtable.c src/core/lib/transport/metadata.c src/core/lib/transport/metadata_batch.c src/core/lib/transport/static_metadata.c @@ -1481,6 +1485,7 @@ add_library(grpc++_unsecure src/core/lib/surface/version.c src/core/lib/transport/byte_stream.c src/core/lib/transport/connectivity_state.c + src/core/lib/transport/hashtable.c src/core/lib/transport/metadata.c src/core/lib/transport/metadata_batch.c src/core/lib/transport/static_metadata.c diff --git a/Makefile b/Makefile index 2a22923442f..674fe91ee71 100644 --- a/Makefile +++ b/Makefile @@ -2613,6 +2613,7 @@ LIBGRPC_SRC = \ src/core/lib/surface/version.c \ src/core/lib/transport/byte_stream.c \ src/core/lib/transport/connectivity_state.c \ + src/core/lib/transport/hashtable.c \ src/core/lib/transport/metadata.c \ src/core/lib/transport/metadata_batch.c \ src/core/lib/transport/static_metadata.c \ @@ -2891,6 +2892,7 @@ LIBGRPC_CRONET_SRC = \ src/core/lib/surface/version.c \ src/core/lib/transport/byte_stream.c \ src/core/lib/transport/connectivity_state.c \ + src/core/lib/transport/hashtable.c \ src/core/lib/transport/metadata.c \ src/core/lib/transport/metadata_batch.c \ src/core/lib/transport/static_metadata.c \ @@ -3158,6 +3160,7 @@ LIBGRPC_TEST_UTIL_SRC = \ src/core/lib/surface/version.c \ src/core/lib/transport/byte_stream.c \ src/core/lib/transport/connectivity_state.c \ + src/core/lib/transport/hashtable.c \ src/core/lib/transport/metadata.c \ src/core/lib/transport/metadata_batch.c \ src/core/lib/transport/static_metadata.c \ @@ -3351,6 +3354,7 @@ LIBGRPC_UNSECURE_SRC = \ src/core/lib/surface/version.c \ src/core/lib/transport/byte_stream.c \ src/core/lib/transport/connectivity_state.c \ + src/core/lib/transport/hashtable.c \ src/core/lib/transport/metadata.c \ src/core/lib/transport/metadata_batch.c \ src/core/lib/transport/static_metadata.c \ @@ -3693,6 +3697,7 @@ LIBGRPC++_SRC = \ src/core/lib/surface/version.c \ src/core/lib/transport/byte_stream.c \ src/core/lib/transport/connectivity_state.c \ + src/core/lib/transport/hashtable.c \ src/core/lib/transport/metadata.c \ src/core/lib/transport/metadata_batch.c \ src/core/lib/transport/static_metadata.c \ @@ -4322,6 +4327,7 @@ LIBGRPC++_UNSECURE_SRC = \ src/core/lib/surface/version.c \ src/core/lib/transport/byte_stream.c \ src/core/lib/transport/connectivity_state.c \ + src/core/lib/transport/hashtable.c \ src/core/lib/transport/metadata.c \ src/core/lib/transport/metadata_batch.c \ src/core/lib/transport/static_metadata.c \ diff --git a/binding.gyp b/binding.gyp index 8aa153b878d..88acd1786b8 100644 --- a/binding.gyp +++ b/binding.gyp @@ -651,6 +651,7 @@ 'src/core/lib/surface/version.c', 'src/core/lib/transport/byte_stream.c', 'src/core/lib/transport/connectivity_state.c', + 'src/core/lib/transport/hashtable.c', 'src/core/lib/transport/metadata.c', 'src/core/lib/transport/metadata_batch.c', 'src/core/lib/transport/static_metadata.c', diff --git a/build.yaml b/build.yaml index fe2558eed31..7e95837ee9a 100644 --- a/build.yaml +++ b/build.yaml @@ -243,6 +243,7 @@ filegroups: - src/core/lib/surface/server.h - src/core/lib/transport/byte_stream.h - src/core/lib/transport/connectivity_state.h + - src/core/lib/transport/hashtable.h - src/core/lib/transport/metadata.h - src/core/lib/transport/metadata_batch.h - src/core/lib/transport/static_metadata.h @@ -336,6 +337,7 @@ filegroups: - src/core/lib/surface/version.c - src/core/lib/transport/byte_stream.c - src/core/lib/transport/connectivity_state.c + - src/core/lib/transport/hashtable.c - src/core/lib/transport/metadata.c - src/core/lib/transport/metadata_batch.c - src/core/lib/transport/static_metadata.c diff --git a/config.m4 b/config.m4 index 6ee121df4e4..f65f617f9ad 100644 --- a/config.m4 +++ b/config.m4 @@ -170,6 +170,7 @@ if test "$PHP_GRPC" != "no"; then src/core/lib/surface/version.c \ src/core/lib/transport/byte_stream.c \ src/core/lib/transport/connectivity_state.c \ + src/core/lib/transport/hashtable.c \ src/core/lib/transport/metadata.c \ src/core/lib/transport/metadata_batch.c \ src/core/lib/transport/static_metadata.c \ diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec index 4581762bdfc..ffa7ca08258 100644 --- a/gRPC-Core.podspec +++ b/gRPC-Core.podspec @@ -326,6 +326,7 @@ Pod::Spec.new do |s| 'src/core/lib/surface/server.h', 'src/core/lib/transport/byte_stream.h', 'src/core/lib/transport/connectivity_state.h', + 'src/core/lib/transport/hashtable.h', 'src/core/lib/transport/metadata.h', 'src/core/lib/transport/metadata_batch.h', 'src/core/lib/transport/static_metadata.h', @@ -501,6 +502,7 @@ Pod::Spec.new do |s| 'src/core/lib/surface/version.c', 'src/core/lib/transport/byte_stream.c', 'src/core/lib/transport/connectivity_state.c', + 'src/core/lib/transport/hashtable.c', 'src/core/lib/transport/metadata.c', 'src/core/lib/transport/metadata_batch.c', 'src/core/lib/transport/static_metadata.c', @@ -701,6 +703,7 @@ Pod::Spec.new do |s| 'src/core/lib/surface/server.h', 'src/core/lib/transport/byte_stream.h', 'src/core/lib/transport/connectivity_state.h', + 'src/core/lib/transport/hashtable.h', 'src/core/lib/transport/metadata.h', 'src/core/lib/transport/metadata_batch.h', 'src/core/lib/transport/static_metadata.h', diff --git a/grpc.gemspec b/grpc.gemspec index 2d4a8ddbcfa..44cd7dd7f75 100755 --- a/grpc.gemspec +++ b/grpc.gemspec @@ -246,6 +246,7 @@ Gem::Specification.new do |s| s.files += %w( src/core/lib/surface/server.h ) s.files += %w( src/core/lib/transport/byte_stream.h ) s.files += %w( src/core/lib/transport/connectivity_state.h ) + s.files += %w( src/core/lib/transport/hashtable.h ) s.files += %w( src/core/lib/transport/metadata.h ) s.files += %w( src/core/lib/transport/metadata_batch.h ) s.files += %w( src/core/lib/transport/static_metadata.h ) @@ -421,6 +422,7 @@ Gem::Specification.new do |s| s.files += %w( src/core/lib/surface/version.c ) s.files += %w( src/core/lib/transport/byte_stream.c ) s.files += %w( src/core/lib/transport/connectivity_state.c ) + s.files += %w( src/core/lib/transport/hashtable.c ) s.files += %w( src/core/lib/transport/metadata.c ) s.files += %w( src/core/lib/transport/metadata_batch.c ) s.files += %w( src/core/lib/transport/static_metadata.c ) diff --git a/package.xml b/package.xml index 87202162603..bf452c3b162 100644 --- a/package.xml +++ b/package.xml @@ -253,6 +253,7 @@ + @@ -428,6 +429,7 @@ + diff --git a/src/core/ext/client_config/method_config.c b/src/core/ext/client_config/method_config.c index 989f7769677..553a7be496a 100644 --- a/src/core/ext/client_config/method_config.c +++ b/src/core/ext/client_config/method_config.c @@ -39,165 +39,214 @@ #include #include +#include "src/core/lib/transport/hashtable.h" #include "src/core/lib/transport/metadata.h" // // grpc_method_config // +// bool vtable + +static void* bool_copy(void* valuep) { + bool value = *(bool*)valuep; + bool* new_value = gpr_malloc(sizeof(bool)); + *new_value = value; + return new_value; +} + +static int bool_cmp(void* v1, void* v2) { + bool b1 = *(bool*)v1; + bool b2 = *(bool*)v2; + if (!b1 && b2) return -1; + if (b1 && !b2) return 1; + return 0; +} + +static grpc_hash_table_vtable bool_vtable = {gpr_free, bool_copy, bool_cmp}; + +// timespec vtable + +static void* timespec_copy(void* valuep) { + gpr_timespec value = *(gpr_timespec*)valuep; + gpr_timespec* new_value = gpr_malloc(sizeof(gpr_timespec)); + *new_value = value; + return new_value; +} + +static int timespec_cmp(void* v1, void* v2) { + return gpr_time_cmp(*(gpr_timespec*)v1, *(gpr_timespec*)v2); +} + +static grpc_hash_table_vtable timespec_vtable = { + gpr_free, timespec_copy, timespec_cmp}; + +// int32 vtable + +static void* int32_copy(void* valuep) { + int32_t value = *(int32_t*)valuep; + int32_t* new_value = gpr_malloc(sizeof(int32_t)); + *new_value = value; + return new_value; +} + +static int int32_cmp(void* v1, void* v2) { + int32_t i1 = *(int32_t*)v1; + int32_t i2 = *(int32_t*)v2; + if (i1 < i2) return -1; + if (i1 > i2) return 1; + return 0; +} + +static grpc_hash_table_vtable int32_vtable = {gpr_free, int32_copy, int32_cmp}; + +// Hash table keys. +#define GRPC_METHOD_CONFIG_WAIT_FOR_READY "grpc.wait_for_ready" // bool +#define GRPC_METHOD_CONFIG_TIMEOUT "grpc.timeout" // gpr_timespec +#define GRPC_METHOD_CONFIG_MAX_REQUEST_MESSAGE_BYTES \ + "grpc.max_request_message_bytes" // int32 +#define GRPC_METHOD_CONFIG_MAX_RESPONSE_MESSAGE_BYTES \ + "grpc.max_response_message_bytes" // int32 + struct grpc_method_config { - gpr_refcount refs; - bool* wait_for_ready; - gpr_timespec* timeout; - int32_t* max_request_message_bytes; - int32_t* max_response_message_bytes; + grpc_hash_table* table; + grpc_mdstr* wait_for_ready_key; + grpc_mdstr* timeout_key; + grpc_mdstr* max_request_message_bytes_key; + grpc_mdstr* max_response_message_bytes_key; }; grpc_method_config* grpc_method_config_create( bool* wait_for_ready, gpr_timespec* timeout, int32_t* max_request_message_bytes, int32_t* max_response_message_bytes) { - grpc_method_config* config = gpr_malloc(sizeof(*config)); - memset(config, 0, sizeof(*config)); - gpr_ref_init(&config->refs, 1); + grpc_method_config* method_config = gpr_malloc(sizeof(grpc_method_config)); + memset(method_config, 0, sizeof(grpc_method_config)); + grpc_hash_table_entry entries[4]; + size_t num_entries = 0; if (wait_for_ready != NULL) { - config->wait_for_ready = gpr_malloc(sizeof(*wait_for_ready)); - *config->wait_for_ready = *wait_for_ready; + method_config->wait_for_ready_key = + grpc_mdstr_from_string(GRPC_METHOD_CONFIG_WAIT_FOR_READY); + entries[num_entries].key = method_config->wait_for_ready_key; + entries[num_entries].value = wait_for_ready; + entries[num_entries].vtable = &bool_vtable; + ++num_entries; } if (timeout != NULL) { - config->timeout = gpr_malloc(sizeof(*timeout)); - *config->timeout = *timeout; + method_config->timeout_key = + grpc_mdstr_from_string(GRPC_METHOD_CONFIG_TIMEOUT); + entries[num_entries].key = method_config->timeout_key; + entries[num_entries].value = timeout; + entries[num_entries].vtable = ×pec_vtable; + ++num_entries; } if (max_request_message_bytes != NULL) { - config->max_request_message_bytes = - gpr_malloc(sizeof(*max_request_message_bytes)); - *config->max_request_message_bytes = *max_request_message_bytes; + method_config->max_request_message_bytes_key = + grpc_mdstr_from_string(GRPC_METHOD_CONFIG_MAX_REQUEST_MESSAGE_BYTES); + entries[num_entries].key = method_config->max_request_message_bytes_key; + entries[num_entries].value = max_request_message_bytes; + entries[num_entries].vtable = &int32_vtable; + ++num_entries; } if (max_response_message_bytes != NULL) { - config->max_response_message_bytes = - gpr_malloc(sizeof(*max_response_message_bytes)); - *config->max_response_message_bytes = *max_response_message_bytes; + method_config->max_response_message_bytes_key = + grpc_mdstr_from_string(GRPC_METHOD_CONFIG_MAX_RESPONSE_MESSAGE_BYTES); + entries[num_entries].key = method_config->max_response_message_bytes_key; + entries[num_entries].value = max_response_message_bytes; + entries[num_entries].vtable = &int32_vtable; + ++num_entries; } - return config; + method_config->table = grpc_hash_table_create(num_entries, entries); + return method_config; } grpc_method_config* grpc_method_config_ref(grpc_method_config* method_config) { - gpr_ref(&method_config->refs); + grpc_hash_table_ref(method_config->table); return method_config; } void grpc_method_config_unref(grpc_method_config* method_config) { - if (gpr_unref(&method_config->refs)) { - gpr_free(method_config->wait_for_ready); - gpr_free(method_config->timeout); - gpr_free(method_config->max_request_message_bytes); - gpr_free(method_config->max_response_message_bytes); - gpr_free(method_config); + if (grpc_hash_table_unref(method_config->table)) { + GRPC_MDSTR_UNREF(method_config->wait_for_ready_key); + GRPC_MDSTR_UNREF(method_config->timeout_key); + GRPC_MDSTR_UNREF(method_config->max_request_message_bytes_key); + GRPC_MDSTR_UNREF(method_config->max_response_message_bytes_key); } } +int grpc_method_config_cmp(grpc_method_config* method_config1, + grpc_method_config* method_config2) { + return grpc_hash_table_cmp(method_config1->table, method_config2->table); +} + bool* grpc_method_config_get_wait_for_ready(grpc_method_config* method_config) { - return method_config->wait_for_ready; + return grpc_hash_table_get(method_config->table, + method_config->wait_for_ready_key); } gpr_timespec* grpc_method_config_get_timeout( grpc_method_config* method_config) { - return method_config->timeout; + return grpc_hash_table_get(method_config->table, method_config->timeout_key); } int32_t* grpc_method_config_get_max_request_message_bytes( grpc_method_config* method_config) { - return method_config->max_request_message_bytes; + return grpc_hash_table_get(method_config->table, + method_config->max_request_message_bytes_key); } int32_t* grpc_method_config_get_max_response_message_bytes( grpc_method_config* method_config) { - return method_config->max_response_message_bytes; + return grpc_hash_table_get(method_config->table, + method_config->max_response_message_bytes_key); } // // grpc_method_config_table // -typedef struct grpc_method_config_table_entry { - grpc_mdstr* path; - grpc_method_config* method_config; -} grpc_method_config_table_entry; - -#define METHOD_CONFIG_TABLE_SIZE 128 -struct grpc_method_config_table { - gpr_refcount refs; - grpc_method_config_table_entry entries[METHOD_CONFIG_TABLE_SIZE]; -}; - -grpc_method_config_table* grpc_method_config_table_create() { - grpc_method_config_table* table = gpr_malloc(sizeof(*table)); - memset(table, 0, sizeof(*table)); - gpr_ref_init(&table->refs, 1); - return table; +static void method_config_unref(void* valuep) { + grpc_method_config_unref(valuep); } -grpc_method_config_table* grpc_method_config_table_ref( - grpc_method_config_table* table) { - if (table != NULL) gpr_ref(&table->refs); - return table; +static void* method_config_ref(void* valuep) { + return grpc_method_config_ref(valuep); } -void grpc_method_config_table_unref(grpc_method_config_table* table) { - if (table != NULL && gpr_unref(&table->refs)) { - for (size_t i = 0; i < GPR_ARRAY_SIZE(table->entries); ++i) { - grpc_method_config_table_entry* entry = &table->entries[i]; - if (entry->path != NULL) { - GRPC_MDSTR_UNREF(entry->path); - grpc_method_config_unref(entry->method_config); - } - } - } +static int method_config_cmp(void* valuep1, void* valuep2) { + return grpc_method_config_cmp(valuep1, valuep2); } -// Helper function for insert and get operations that performs quadratic -// probing (https://en.wikipedia.org/wiki/Quadratic_probing). -static size_t grpc_method_config_table_find_index( - grpc_method_config_table* table, grpc_mdstr* path, bool find_empty) { - for (size_t i = 0; i < GPR_ARRAY_SIZE(table->entries); ++i) { - const size_t idx = (path->hash + i * i) % GPR_ARRAY_SIZE(table->entries); - if (table->entries[idx].path == NULL) - return find_empty ? idx : GPR_ARRAY_SIZE(table->entries); - if (table->entries[idx].path == path) return idx; +static const grpc_hash_table_vtable method_config_table_vtable = { + method_config_unref, method_config_ref, method_config_cmp}; + +grpc_method_config_table* grpc_method_config_table_create( + size_t num_entries, grpc_method_config_table_entry* entries) { + grpc_hash_table_entry hash_table_entries[num_entries]; + for (size_t i = 0; i < num_entries; ++i) { + hash_table_entries[i].key = entries[i].method_name; + hash_table_entries[i].value = entries[i].method_config; + hash_table_entries[i].vtable = &method_config_table_vtable; } - return GPR_ARRAY_SIZE(table->entries) + 1; // Not found. + return grpc_hash_table_create(num_entries, hash_table_entries); } -static void grpc_method_config_table_insert(grpc_method_config_table* table, - grpc_mdstr* path, - grpc_method_config* config) { - const size_t idx = - grpc_method_config_table_find_index(table, path, true /* find_empty */); - // This can happen if the table is full. - GPR_ASSERT(idx != GPR_ARRAY_SIZE(table->entries)); - grpc_method_config_table_entry* entry = &table->entries[idx]; - entry->path = GRPC_MDSTR_REF(path); - entry->method_config = grpc_method_config_ref(config); +grpc_method_config_table* grpc_method_config_table_ref( + grpc_method_config_table* table) { + return grpc_hash_table_ref(table); } -static grpc_method_config* grpc_method_config_table_get( - grpc_method_config_table* table, grpc_mdstr* path) { - const size_t idx = - grpc_method_config_table_find_index(table, path, false /* find_empty */); - if (idx == GPR_ARRAY_SIZE(table->entries)) return NULL; // Not found. - return table->entries[idx].method_config; +void grpc_method_config_table_unref(grpc_method_config_table* table) { + grpc_hash_table_unref(table); } -void grpc_method_config_table_add_method_config( - grpc_method_config_table* table, grpc_mdstr** paths, size_t num_paths, - grpc_method_config* method_config) { - for (size_t i = 0; i < num_paths; ++i) { - grpc_method_config_table_insert(table, paths[i], method_config); - } +int grpc_method_config_table_cmp(grpc_method_config_table* table1, + grpc_method_config_table* table2) { + return grpc_hash_table_cmp(table1, table2); } grpc_method_config* grpc_method_config_table_get_method_config( grpc_method_config_table* table, grpc_mdstr* path) { - grpc_method_config* method_config = grpc_method_config_table_get(table, path); + grpc_method_config* method_config = grpc_hash_table_get(table, path); // If we didn't find a match for the path, try looking for a wildcard // entry (i.e., change "/service/method" to "/service/*"). if (method_config == NULL) { @@ -209,7 +258,7 @@ grpc_method_config* grpc_method_config_table_get_method_config( buf[len] = '*'; buf[len + 1] = '\0'; grpc_mdstr* wildcard_path = grpc_mdstr_from_string(buf); - method_config = grpc_method_config_table_get(table, wildcard_path); + method_config = grpc_hash_table_get(table, wildcard_path); GRPC_MDSTR_UNREF(wildcard_path); } return grpc_method_config_ref(method_config); @@ -224,52 +273,7 @@ static void destroy_arg(void* p) { } static int cmp_arg(void* p1, void* p2) { - grpc_method_config_table* t1 = p1; - grpc_method_config_table* t2 = p2; - for (size_t i = 0; i < GPR_ARRAY_SIZE(t1->entries); ++i) { - grpc_method_config_table_entry* e1 = &t1->entries[i]; - grpc_method_config_table_entry* e2 = &t2->entries[i]; - // Compare paths by hash value. - if (e1->path->hash < e2->path->hash) return -1; - if (e1->path->hash > e2->path->hash) return 1; - // Compare wait_for_ready. - const bool wait_for_ready1 = - e1->method_config->wait_for_ready == NULL - ? false : *e1->method_config->wait_for_ready; - const bool wait_for_ready2 = - e2->method_config->wait_for_ready == NULL - ? false : *e2->method_config->wait_for_ready; - if (wait_for_ready1 < wait_for_ready2) return -1; - if (wait_for_ready1 > wait_for_ready2) return 1; - // Compare timeout. - const gpr_timespec timeout1 = - e1->method_config->timeout == NULL - ? gpr_inf_past(GPR_CLOCK_MONOTONIC) : *e1->method_config->timeout; - const gpr_timespec timeout2 = - e2->method_config->timeout == NULL - ? gpr_inf_past(GPR_CLOCK_MONOTONIC) : *e2->method_config->timeout; - const int timeout_result = gpr_time_cmp(timeout1, timeout2); - if (timeout_result != 0) return timeout_result; - // Compare max_request_message_bytes. - const int32_t max_request_message_bytes1 = - e1->method_config->max_request_message_bytes == NULL - ? -1 : *e1->method_config->max_request_message_bytes; - const int32_t max_request_message_bytes2 = - e2->method_config->max_request_message_bytes == NULL - ? -1 : *e2->method_config->max_request_message_bytes; - if (max_request_message_bytes1 < max_request_message_bytes2) return -1; - if (max_request_message_bytes1 > max_request_message_bytes2) return 1; - // Compare max_response_message_bytes. - const int32_t max_response_message_bytes1 = - e1->method_config->max_response_message_bytes == NULL - ? -1 : *e1->method_config->max_response_message_bytes; - const int32_t max_response_message_bytes2 = - e2->method_config->max_response_message_bytes == NULL - ? -1 : *e2->method_config->max_response_message_bytes; - if (max_response_message_bytes1 < max_response_message_bytes2) return -1; - if (max_response_message_bytes1 > max_response_message_bytes2) return 1; - } - return 0; + return grpc_method_config_table_cmp(p1, p2); } static grpc_arg_pointer_vtable arg_vtable = {copy_arg, destroy_arg, cmp_arg}; diff --git a/src/core/ext/client_config/method_config.h b/src/core/ext/client_config/method_config.h index 2be0cd1006b..e95a5583be2 100644 --- a/src/core/ext/client_config/method_config.h +++ b/src/core/ext/client_config/method_config.h @@ -37,6 +37,7 @@ #include #include +#include "src/core/lib/transport/hashtable.h" #include "src/core/lib/transport/metadata.h" /// Per-method configuration. @@ -50,6 +51,9 @@ grpc_method_config* grpc_method_config_create( grpc_method_config* grpc_method_config_ref(grpc_method_config* method_config); void grpc_method_config_unref(grpc_method_config* method_config); +int grpc_method_config_cmp(grpc_method_config* method_config1, + grpc_method_config* method_config2); + /// These methods return NULL if the requested field is unset. /// The caller does NOT take ownership of the result. bool* grpc_method_config_get_wait_for_ready(grpc_method_config* method_config); @@ -60,23 +64,26 @@ int32_t* grpc_method_config_get_max_response_message_bytes( grpc_method_config* method_config); /// A table of method configs. -typedef struct grpc_method_config_table grpc_method_config_table; +typedef grpc_hash_table grpc_method_config_table; + +typedef struct grpc_method_config_table_entry { + /// The name is of one of the following forms: + /// service/method -- specifies exact service and method name + /// service/* -- matches all methods for the specified service + grpc_mdstr* method_name; + grpc_method_config* method_config; +} grpc_method_config_table_entry; -grpc_method_config_table* grpc_method_config_table_create(); +/// Takes new references to all keys and values in \a entries. +grpc_method_config_table* grpc_method_config_table_create( + size_t num_entries, grpc_method_config_table_entry* entries); grpc_method_config_table* grpc_method_config_table_ref( grpc_method_config_table* table); void grpc_method_config_table_unref(grpc_method_config_table* table); -/// Adds \a method_config to \a table. \a paths indicates the set of path -/// names for which this config applies. Each name is of one of the -/// following forms: -/// service/method -- specifies exact service and method name -/// service/* -- matches all methods for the specified service -/// Takes new references to all elements of \a paths and to \a method_config. -void grpc_method_config_table_add_method_config( - grpc_method_config_table* table, grpc_mdstr** paths, size_t num_paths, - grpc_method_config* method_config); +int grpc_method_config_table_cmp(grpc_method_config_table* table1, + grpc_method_config_table* table2); /// Returns NULL if the method has no config. /// Caller owns a reference to result. diff --git a/src/core/lib/transport/hashtable.c b/src/core/lib/transport/hashtable.c new file mode 100644 index 00000000000..89e26409693 --- /dev/null +++ b/src/core/lib/transport/hashtable.c @@ -0,0 +1,139 @@ +// +// Copyright 2016, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +#include "src/core/lib/transport/hashtable.h" + +#include +#include + +#include +#include + +#include "src/core/lib/transport/metadata.h" + +struct grpc_hash_table { + gpr_refcount refs; + size_t num_entries; + grpc_hash_table_entry* entries; +}; + +// Helper function for insert and get operations that performs quadratic +// probing (https://en.wikipedia.org/wiki/Quadratic_probing). +static size_t grpc_hash_table_find_index( + grpc_hash_table* table, grpc_mdstr* key, bool find_empty) { + for (size_t i = 0; i < table->num_entries; ++i) { + const size_t idx = (key->hash + i * i) % table->num_entries; + if (table->entries[idx].key == NULL) + return find_empty ? idx : table->num_entries; + if (table->entries[idx].key == key) return idx; + } + return table->num_entries; // Not found. +} + +static void grpc_hash_table_add(grpc_hash_table* table, grpc_mdstr* key, + void* value, + const grpc_hash_table_vtable* vtable) { + GPR_ASSERT(value != NULL); + const size_t idx = + grpc_hash_table_find_index(table, key, true /* find_empty */); + // This can happen if the table is full. + GPR_ASSERT(idx != table->num_entries); + grpc_hash_table_entry* entry = &table->entries[idx]; + entry->key = GRPC_MDSTR_REF(key); + entry->value = vtable->copy_value(value); + entry->vtable = vtable; +} + +grpc_hash_table* grpc_hash_table_create(size_t num_entries, + grpc_hash_table_entry* entries) { + grpc_hash_table* table = gpr_malloc(sizeof(*table)); + memset(table, 0, sizeof(*table)); + gpr_ref_init(&table->refs, 1); + // Quadratic chaining gets best performance when the table is no more + // than half full. + table->num_entries = num_entries * 2; + const size_t entry_size = sizeof(grpc_hash_table_entry) * table->num_entries; + table->entries = gpr_malloc(entry_size); + memset(table->entries, 0, entry_size); + for (size_t i = 0; i < num_entries; ++i) { + grpc_hash_table_entry* entry = &entries[i]; + grpc_hash_table_add(table, entry->key, entry->value, entry->vtable); + } + return table; +} + +grpc_hash_table* grpc_hash_table_ref(grpc_hash_table* table) { + if (table != NULL) gpr_ref(&table->refs); + return table; +} + +int grpc_hash_table_unref(grpc_hash_table* table) { + if (table != NULL && gpr_unref(&table->refs)) { + for (size_t i = 0; i < table->num_entries; ++i) { + grpc_hash_table_entry* entry = &table->entries[i]; + if (entry->key != NULL) { + GRPC_MDSTR_UNREF(entry->key); + entry->vtable->destroy_value(entry->value); + } + } + gpr_free(table->entries); + gpr_free(table); + return 1; + } + return 0; +} + +void* grpc_hash_table_get(grpc_hash_table* table, grpc_mdstr* key) { + const size_t idx = + grpc_hash_table_find_index(table, key, false /* find_empty */); + if (idx == table->num_entries) return NULL; // Not found. + return table->entries[idx].value; +} + +int grpc_hash_table_cmp(grpc_hash_table* table1, grpc_hash_table* table2) { + // Compare by num_entries. + if (table1->num_entries < table2->num_entries) return -1; + if (table1->num_entries > table2->num_entries) return 1; + for (size_t i = 0; i < table1->num_entries; ++i) { + grpc_hash_table_entry* e1 = &table1->entries[i]; + grpc_hash_table_entry* e2 = &table2->entries[i]; + // Compare keys by hash value. + if (e1->key->hash < e2->key->hash) return -1; + if (e1->key->hash > e2->key->hash) return 1; + // Compare by vtable (pointer equality). + if (e1->vtable < e2->vtable) return -1; + if (e1->vtable > e2->vtable) return 1; + // Compare values via vtable. + const int value_result = e1->vtable->compare_value(e1->value, e2->value); + if (value_result != 0) return value_result; + } + return 0; +} diff --git a/src/core/lib/transport/hashtable.h b/src/core/lib/transport/hashtable.h new file mode 100644 index 00000000000..93f0642c172 --- /dev/null +++ b/src/core/lib/transport/hashtable.h @@ -0,0 +1,82 @@ +/* + * Copyright 2016, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GRPC_CORE_LIB_TRANSPORT_HASHTABLE_H +#define GRPC_CORE_LIB_TRANSPORT_HASHTABLE_H + +#include "src/core/lib/transport/metadata.h" + +/** Hash table implementation. + * + * This implementation uses open addressing + * (https://en.wikipedia.org/wiki/Open_addressing) with quadratic + * probing (https://en.wikipedia.org/wiki/Quadratic_probing). + * This means that the hash table is of fixed size and cannot contain + * more than that number of elements. + * + * The keys are grpc_mdstr objects. The values are arbitrary pointers + * with a common vtable. + * + * Hash tables are intentionally immutable, to avoid the need for locking. + */ + +typedef struct grpc_hash_table grpc_hash_table; + +typedef struct grpc_hash_table_vtable { + void (*destroy_value)(void* value); + void* (*copy_value)(void* value); + int (*compare_value)(void* value1, void* value2); +} grpc_hash_table_vtable; + +typedef struct grpc_hash_table_entry { + grpc_mdstr* key; + void* value; /* Must not be NULL. */ + const grpc_hash_table_vtable* vtable; +} grpc_hash_table_entry; + +/** Creates a new hash table of containing \a entries, which is an array + of length \a num_entries. + Creates its own copy of all keys and values from \a entries. */ +grpc_hash_table* grpc_hash_table_create(size_t num_entries, + grpc_hash_table_entry* entries); + +grpc_hash_table* grpc_hash_table_ref(grpc_hash_table* table); +/** Returns 1 when \a table is destroyed. */ +int grpc_hash_table_unref(grpc_hash_table* table); + +/** Returns the value from \a table associated with \a key. + Returns NULL if \a key is not found. */ +void* grpc_hash_table_get(grpc_hash_table* table, grpc_mdstr* key); + +/** Compares two hash tables. */ +int grpc_hash_table_cmp(grpc_hash_table* table1, grpc_hash_table* table2); + +#endif /* GRPC_CORE_LIB_TRANSPORT_HASHTABLE_H */ diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py index f9308ba7a56..315d469a153 100644 --- a/src/python/grpcio/grpc_core_dependencies.py +++ b/src/python/grpcio/grpc_core_dependencies.py @@ -164,6 +164,7 @@ CORE_SOURCE_FILES = [ 'src/core/lib/surface/version.c', 'src/core/lib/transport/byte_stream.c', 'src/core/lib/transport/connectivity_state.c', + 'src/core/lib/transport/hashtable.c', 'src/core/lib/transport/metadata.c', 'src/core/lib/transport/metadata_batch.c', 'src/core/lib/transport/static_metadata.c', diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal index ce21a4ea003..1619194d4a3 100644 --- a/tools/doxygen/Doxyfile.c++.internal +++ b/tools/doxygen/Doxyfile.c++.internal @@ -947,6 +947,7 @@ src/core/lib/surface/lame_client.h \ src/core/lib/surface/server.h \ src/core/lib/transport/byte_stream.h \ src/core/lib/transport/connectivity_state.h \ +src/core/lib/transport/hashtable.h \ src/core/lib/transport/metadata.h \ src/core/lib/transport/metadata_batch.h \ src/core/lib/transport/static_metadata.h \ @@ -1072,6 +1073,7 @@ src/core/lib/surface/validate_metadata.c \ src/core/lib/surface/version.c \ src/core/lib/transport/byte_stream.c \ src/core/lib/transport/connectivity_state.c \ +src/core/lib/transport/hashtable.c \ src/core/lib/transport/metadata.c \ src/core/lib/transport/metadata_batch.c \ src/core/lib/transport/static_metadata.c \ diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal index 9ea6695f242..c9317396f61 100644 --- a/tools/doxygen/Doxyfile.core.internal +++ b/tools/doxygen/Doxyfile.core.internal @@ -863,6 +863,7 @@ src/core/lib/surface/lame_client.h \ src/core/lib/surface/server.h \ src/core/lib/transport/byte_stream.h \ src/core/lib/transport/connectivity_state.h \ +src/core/lib/transport/hashtable.h \ src/core/lib/transport/metadata.h \ src/core/lib/transport/metadata_batch.h \ src/core/lib/transport/static_metadata.h \ @@ -1038,6 +1039,7 @@ src/core/lib/surface/validate_metadata.c \ src/core/lib/surface/version.c \ src/core/lib/transport/byte_stream.c \ src/core/lib/transport/connectivity_state.c \ +src/core/lib/transport/hashtable.c \ src/core/lib/transport/metadata.c \ src/core/lib/transport/metadata_batch.c \ src/core/lib/transport/static_metadata.c \ diff --git a/tools/run_tests/sources_and_headers.json b/tools/run_tests/sources_and_headers.json index f6889c8f3a2..0fe6cdf6b96 100644 --- a/tools/run_tests/sources_and_headers.json +++ b/tools/run_tests/sources_and_headers.json @@ -6049,6 +6049,7 @@ "src/core/lib/surface/server.h", "src/core/lib/transport/byte_stream.h", "src/core/lib/transport/connectivity_state.h", + "src/core/lib/transport/hashtable.h", "src/core/lib/transport/metadata.h", "src/core/lib/transport/metadata_batch.h", "src/core/lib/transport/static_metadata.h", @@ -6229,6 +6230,8 @@ "src/core/lib/transport/byte_stream.h", "src/core/lib/transport/connectivity_state.c", "src/core/lib/transport/connectivity_state.h", + "src/core/lib/transport/hashtable.c", + "src/core/lib/transport/hashtable.h", "src/core/lib/transport/metadata.c", "src/core/lib/transport/metadata.h", "src/core/lib/transport/metadata_batch.c", diff --git a/vsprojects/vcxproj/grpc++/grpc++.vcxproj b/vsprojects/vcxproj/grpc++/grpc++.vcxproj index 88ddecf426c..92a7e02e52c 100644 --- a/vsprojects/vcxproj/grpc++/grpc++.vcxproj +++ b/vsprojects/vcxproj/grpc++/grpc++.vcxproj @@ -447,6 +447,7 @@ + @@ -693,6 +694,8 @@ + + diff --git a/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters b/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters index a6616449d34..9282b52eef0 100644 --- a/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters +++ b/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters @@ -358,6 +358,9 @@ src\core\lib\transport + + src\core\lib\transport + src\core\lib\transport @@ -944,6 +947,9 @@ src\core\lib\transport + + src\core\lib\transport + src\core\lib\transport diff --git a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj index 99cee2830a2..0270fe48369 100644 --- a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj +++ b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj @@ -443,6 +443,7 @@ + @@ -679,6 +680,8 @@ + + diff --git a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters index e1b6b2f3272..8863237f43e 100644 --- a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters +++ b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters @@ -343,6 +343,9 @@ src\core\lib\transport + + src\core\lib\transport + src\core\lib\transport @@ -917,6 +920,9 @@ src\core\lib\transport + + src\core\lib\transport + src\core\lib\transport diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj b/vsprojects/vcxproj/grpc/grpc.vcxproj index ba2174f429e..b2352d74f45 100644 --- a/vsprojects/vcxproj/grpc/grpc.vcxproj +++ b/vsprojects/vcxproj/grpc/grpc.vcxproj @@ -372,6 +372,7 @@ + @@ -636,6 +637,8 @@ + + diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters index ee3e7a85d31..ee7825ae882 100644 --- a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters +++ b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters @@ -262,6 +262,9 @@ src\core\lib\transport + + src\core\lib\transport + src\core\lib\transport @@ -902,6 +905,9 @@ src\core\lib\transport + + src\core\lib\transport + src\core\lib\transport diff --git a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj index 21d9fc95296..f09be1528be 100644 --- a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj +++ b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj @@ -264,6 +264,7 @@ + @@ -480,6 +481,8 @@ + + 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 09a32482cd6..7be3b76d233 100644 --- a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters +++ b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters @@ -313,6 +313,9 @@ src\core\lib\transport + + src\core\lib\transport + src\core\lib\transport @@ -680,6 +683,9 @@ src\core\lib\transport + + src\core\lib\transport + src\core\lib\transport diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj index be02a4fa927..09a1e2386d5 100644 --- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj +++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj @@ -362,6 +362,7 @@ + @@ -604,6 +605,8 @@ + + diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters index 482da9b984e..df7a9b9b432 100644 --- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters +++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters @@ -265,6 +265,9 @@ src\core\lib\transport + + src\core\lib\transport + src\core\lib\transport @@ -812,6 +815,9 @@ src\core\lib\transport + + src\core\lib\transport + src\core\lib\transport From 996e95b4ad4e401dc8b04ae9cc092bd167307e10 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Tue, 27 Sep 2016 10:55:37 -0700 Subject: [PATCH 10/48] Use per-method max message size limits. --- src/core/lib/channel/message_size_filter.c | 68 +++++++++++++++++----- 1 file changed, 55 insertions(+), 13 deletions(-) diff --git a/src/core/lib/channel/message_size_filter.c b/src/core/lib/channel/message_size_filter.c index a254fe3997f..e34e365d2cc 100644 --- a/src/core/lib/channel/message_size_filter.c +++ b/src/core/lib/channel/message_size_filter.c @@ -39,11 +39,14 @@ #include #include "src/core/lib/channel/channel_args.h" +#include "src/core/ext/client_config/method_config.h" // The protobuf library will (by default) start warning at 100 megs. #define DEFAULT_MAX_MESSAGE_LENGTH (4 * 1024 * 1024) typedef struct call_data { + int max_send_size; + int max_recv_size; // Receive closures are chained: we inject this closure as the // recv_message_ready up-call on transport_stream_op, and remember to // call our next_recv_message_ready member after handling it. @@ -55,8 +58,10 @@ typedef struct call_data { } call_data; typedef struct channel_data { - size_t max_send_size; - size_t max_recv_size; + int max_send_size; + int max_recv_size; + // Method config table. + grpc_method_config_table* method_config_table; } channel_data; // Callback invoked when we receive a message. Here we check the max @@ -65,13 +70,12 @@ static void recv_message_ready(grpc_exec_ctx* exec_ctx, void* user_data, grpc_error* error) { grpc_call_element* elem = user_data; call_data* calld = elem->call_data; - channel_data* chand = elem->channel_data; - if (*calld->recv_message != NULL && - (*calld->recv_message)->length > chand->max_recv_size) { + if (*calld->recv_message != NULL && calld->max_recv_size >= 0 && + (*calld->recv_message)->length > (size_t)calld->max_recv_size) { char* message_string; gpr_asprintf( - &message_string, "Received message larger than max (%u vs. %lu)", - (*calld->recv_message)->length, (unsigned long)chand->max_recv_size); + &message_string, "Received message larger than max (%u vs. %d)", + (*calld->recv_message)->length, calld->max_recv_size); gpr_slice message = gpr_slice_from_copied_string(message_string); gpr_free(message_string); grpc_call_element_send_close_with_message( @@ -86,13 +90,12 @@ static void start_transport_stream_op(grpc_exec_ctx* exec_ctx, grpc_call_element* elem, grpc_transport_stream_op* op) { call_data* calld = elem->call_data; - channel_data* chand = elem->channel_data; // Check max send message size. - if (op->send_message != NULL && - op->send_message->length > chand->max_send_size) { + if (op->send_message != NULL && calld->max_send_size >= 0 && + op->send_message->length > (size_t)calld->max_send_size) { char* message_string; - gpr_asprintf(&message_string, "Sent message larger than max (%u vs. %lu)", - op->send_message->length, (unsigned long)chand->max_send_size); + gpr_asprintf(&message_string, "Sent message larger than max (%u vs. %d)", + op->send_message->length, calld->max_send_size); gpr_slice message = gpr_slice_from_copied_string(message_string); gpr_free(message_string); grpc_call_element_send_close_with_message( @@ -112,9 +115,37 @@ static void start_transport_stream_op(grpc_exec_ctx* exec_ctx, static grpc_error* init_call_elem(grpc_exec_ctx* exec_ctx, grpc_call_element* elem, grpc_call_element_args* args) { + channel_data* chand = elem->channel_data; call_data* calld = elem->call_data; calld->next_recv_message_ready = NULL; grpc_closure_init(&calld->recv_message_ready, recv_message_ready, elem); + // Get max sizes from channel data, then merge in per-method config values. + // Note: Per-method config is only available on the client, so we + // apply the max request size to the send limit and the max response + // size to the receive limit. + calld->max_send_size = chand->max_send_size; + calld->max_recv_size = chand->max_recv_size; + if (chand->method_config_table != NULL) { + grpc_method_config* method_config = + grpc_method_config_table_get_method_config(chand->method_config_table, + args->path); + if (method_config != NULL) { + int32_t* max_request_message_bytes = + grpc_method_config_get_max_request_message_bytes(method_config); + if (max_request_message_bytes != NULL && + (*max_request_message_bytes < calld->max_send_size || + calld->max_send_size < 0)) { + calld->max_send_size = *max_request_message_bytes; + } + int32_t* max_response_message_bytes = + grpc_method_config_get_max_response_message_bytes(method_config); + if (max_response_message_bytes != NULL && + (*max_response_message_bytes < calld->max_recv_size || + calld->max_recv_size < 0)) { + calld->max_recv_size = *max_response_message_bytes; + } + } + } return GRPC_ERROR_NONE; } @@ -145,11 +176,22 @@ static void init_channel_elem(grpc_exec_ctx* exec_ctx, &args->channel_args->args[i], options); } } + // Get method config table from channel args. + const grpc_arg *channel_arg = grpc_channel_args_find( + args->channel_args, GRPC_ARG_SERVICE_CONFIG); + if (channel_arg != NULL) { + GPR_ASSERT(channel_arg->type == GRPC_ARG_POINTER); + chand->method_config_table = grpc_method_config_table_ref( + (grpc_method_config_table *)channel_arg->value.pointer.p); + } } // Destructor for channel_data. static void destroy_channel_elem(grpc_exec_ctx* exec_ctx, - grpc_channel_element* elem) {} + grpc_channel_element* elem) { + channel_data* chand = elem->channel_data; + grpc_method_config_table_unref(chand->method_config_table); +} const grpc_channel_filter grpc_message_size_filter = { start_transport_stream_op, From 6336ef7bad13fbadddcfc12a7b253db6e6dfdbe7 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Wed, 28 Sep 2016 14:23:05 -0700 Subject: [PATCH 11/48] Use per-method wait_until_ready value. --- src/core/ext/client_config/client_channel.c | 36 ++++++++++++++++++--- src/core/lib/channel/deadline_filter.c | 20 ++++-------- src/core/lib/channel/deadline_filter.h | 2 +- 3 files changed, 40 insertions(+), 18 deletions(-) diff --git a/src/core/ext/client_config/client_channel.c b/src/core/ext/client_config/client_channel.c index 7a80975278e..3860f65f95a 100644 --- a/src/core/ext/client_config/client_channel.c +++ b/src/core/ext/client_config/client_channel.c @@ -421,6 +421,9 @@ typedef struct client_channel_call_data { grpc_deadline_state deadline_state; gpr_timespec deadline; + enum { WAIT_FOR_READY_UNSET, WAIT_FOR_READY_FALSE, WAIT_FOR_READY_TRUE } + wait_for_ready_from_service_config; + // Request path. grpc_mdstr *path; @@ -737,12 +740,24 @@ retry: calld->connected_subchannel == NULL && op->send_initial_metadata != NULL) { calld->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL; + // If the application explicitly set wait_for_ready, use that. + // Otherwise, if the service config specified a value for this + // method, use that. + uint32_t initial_metadata_flags = op->send_initial_metadata_flags; + if ((initial_metadata_flags & + GRPC_INITIAL_METADATA_WAIT_FOR_READY_EXPLICITLY_SET) == 0 && + calld->wait_for_ready_from_service_config != WAIT_FOR_READY_UNSET) { + if (calld->wait_for_ready_from_service_config == WAIT_FOR_READY_TRUE) { + initial_metadata_flags |= GRPC_INITIAL_METADATA_WAIT_FOR_READY; + } else { + initial_metadata_flags &= ~GRPC_INITIAL_METADATA_WAIT_FOR_READY; + } + } grpc_closure_init(&calld->next_step, subchannel_ready, calld); GRPC_CALL_STACK_REF(calld->owning_call, "pick_subchannel"); if (pick_subchannel(exec_ctx, elem, op->send_initial_metadata, - op->send_initial_metadata_flags, - &calld->connected_subchannel, &calld->next_step, - GRPC_ERROR_NONE)) { + initial_metadata_flags, &calld->connected_subchannel, + &calld->next_step, GRPC_ERROR_NONE)) { calld->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING; GRPC_CALL_STACK_UNREF(exec_ctx, calld->owning_call, "pick_subchannel"); } @@ -782,7 +797,20 @@ static grpc_error *cc_init_call_elem(grpc_exec_ctx *exec_ctx, ? NULL : grpc_method_config_table_ref(chand->method_config_table); gpr_mu_unlock(&chand->mu); - grpc_deadline_state_init(exec_ctx, elem, args, method_config_table); + grpc_method_config *method_config = + method_config_table == NULL + ? NULL + : grpc_method_config_table_get_method_config(method_config_table, + args->path); + grpc_deadline_state_init(exec_ctx, elem, args, method_config); + calld->wait_for_ready_from_service_config = WAIT_FOR_READY_UNSET; + if (method_config != NULL) { + bool* wait_for_ready = grpc_method_config_get_wait_for_ready(method_config); + if (wait_for_ready != NULL) { + calld->wait_for_ready_from_service_config = + *wait_for_ready ? WAIT_FOR_READY_TRUE : WAIT_FOR_READY_FALSE; + } + } grpc_method_config_table_unref(chand->method_config_table); calld->deadline = args->deadline; calld->path = GRPC_MDSTR_REF(args->path); diff --git a/src/core/lib/channel/deadline_filter.c b/src/core/lib/channel/deadline_filter.c index 89dc8dd6e8c..5216338833d 100644 --- a/src/core/lib/channel/deadline_filter.c +++ b/src/core/lib/channel/deadline_filter.c @@ -124,7 +124,7 @@ static void start_timer_after_init(grpc_exec_ctx* exec_ctx, void* arg, void grpc_deadline_state_init(grpc_exec_ctx* exec_ctx, grpc_call_element* elem, grpc_call_element_args* args, - grpc_method_config_table* method_config_table) { + grpc_method_config* method_config) { grpc_deadline_state* deadline_state = elem->call_data; memset(deadline_state, 0, sizeof(*deadline_state)); deadline_state->call_stack = args->call_stack; @@ -133,16 +133,11 @@ void grpc_deadline_state_init(grpc_exec_ctx* exec_ctx, grpc_call_element* elem, // set on clients with a finite deadline. gpr_timespec deadline = gpr_convert_clock_type(args->deadline, GPR_CLOCK_MONOTONIC); - if (method_config_table != NULL) { - grpc_method_config* method_config = - grpc_method_config_table_get_method_config(method_config_table, - args->path); - if (method_config != NULL) { - gpr_timespec* per_method_deadline = - grpc_method_config_get_timeout(method_config); - if (per_method_deadline != NULL) { - deadline = gpr_time_min(deadline, *per_method_deadline); - } + if (method_config != NULL) { + gpr_timespec* per_method_deadline = + grpc_method_config_get_timeout(method_config); + if (per_method_deadline != NULL) { + deadline = gpr_time_min(deadline, *per_method_deadline); } } if (gpr_time_cmp(deadline, gpr_inf_future(GPR_CLOCK_MONOTONIC)) != 0) { @@ -222,8 +217,7 @@ static grpc_error* init_call_elem(grpc_exec_ctx* exec_ctx, grpc_call_element_args* args) { // Note: size of call data is different between client and server. memset(elem->call_data, 0, elem->filter->sizeof_call_data); - grpc_deadline_state_init(exec_ctx, elem, args, - NULL /* method_config_table */); + grpc_deadline_state_init(exec_ctx, elem, args, NULL /* method_config */); return GRPC_ERROR_NONE; } diff --git a/src/core/lib/channel/deadline_filter.h b/src/core/lib/channel/deadline_filter.h index 2fcee0b9ef0..ce6e8ea974d 100644 --- a/src/core/lib/channel/deadline_filter.h +++ b/src/core/lib/channel/deadline_filter.h @@ -66,7 +66,7 @@ typedef struct grpc_deadline_state { // after the function returns. void grpc_deadline_state_init(grpc_exec_ctx* exec_ctx, grpc_call_element* elem, grpc_call_element_args* args, - grpc_method_config_table* method_config_table); + grpc_method_config* method_config); void grpc_deadline_state_destroy(grpc_exec_ctx* exec_ctx, grpc_call_element* elem); void grpc_deadline_state_client_start_transport_stream_op( From d51e0352c5460a0c050a026dd4d2c1b498ddb57f Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Fri, 30 Sep 2016 08:23:30 -0700 Subject: [PATCH 12/48] Various fixes and clean-ups. --- src/core/ext/client_config/client_channel.c | 4 +++- src/core/ext/client_config/method_config.c | 19 ++++++++++--------- src/core/ext/client_config/method_config.h | 2 +- src/core/ext/client_config/resolver_result.c | 5 ----- src/core/ext/client_config/resolver_result.h | 2 +- src/core/lib/channel/channel_args.c | 4 +++- src/core/lib/channel/channel_args.h | 4 +--- src/core/lib/transport/hashtable.c | 2 +- 8 files changed, 20 insertions(+), 22 deletions(-) diff --git a/src/core/ext/client_config/client_channel.c b/src/core/ext/client_config/client_channel.c index 3860f65f95a..026d3a51b84 100644 --- a/src/core/ext/client_config/client_channel.c +++ b/src/core/ext/client_config/client_channel.c @@ -811,7 +811,9 @@ static grpc_error *cc_init_call_elem(grpc_exec_ctx *exec_ctx, *wait_for_ready ? WAIT_FOR_READY_TRUE : WAIT_FOR_READY_FALSE; } } - grpc_method_config_table_unref(chand->method_config_table); + if (method_config_table != NULL) { + grpc_method_config_table_unref(method_config_table); + } calld->deadline = args->deadline; calld->path = GRPC_MDSTR_REF(args->path); calld->cancel_error = GRPC_ERROR_NONE; diff --git a/src/core/ext/client_config/method_config.c b/src/core/ext/client_config/method_config.c index 553a7be496a..95efe492a95 100644 --- a/src/core/ext/client_config/method_config.c +++ b/src/core/ext/client_config/method_config.c @@ -121,35 +121,35 @@ grpc_method_config* grpc_method_config_create( int32_t* max_request_message_bytes, int32_t* max_response_message_bytes) { grpc_method_config* method_config = gpr_malloc(sizeof(grpc_method_config)); memset(method_config, 0, sizeof(grpc_method_config)); + method_config->wait_for_ready_key = + grpc_mdstr_from_string(GRPC_METHOD_CONFIG_WAIT_FOR_READY); + method_config->timeout_key = + grpc_mdstr_from_string(GRPC_METHOD_CONFIG_TIMEOUT); + method_config->max_request_message_bytes_key = + grpc_mdstr_from_string(GRPC_METHOD_CONFIG_MAX_REQUEST_MESSAGE_BYTES); + method_config->max_response_message_bytes_key = + grpc_mdstr_from_string(GRPC_METHOD_CONFIG_MAX_RESPONSE_MESSAGE_BYTES); grpc_hash_table_entry entries[4]; size_t num_entries = 0; if (wait_for_ready != NULL) { - method_config->wait_for_ready_key = - grpc_mdstr_from_string(GRPC_METHOD_CONFIG_WAIT_FOR_READY); entries[num_entries].key = method_config->wait_for_ready_key; entries[num_entries].value = wait_for_ready; entries[num_entries].vtable = &bool_vtable; ++num_entries; } if (timeout != NULL) { - method_config->timeout_key = - grpc_mdstr_from_string(GRPC_METHOD_CONFIG_TIMEOUT); entries[num_entries].key = method_config->timeout_key; entries[num_entries].value = timeout; entries[num_entries].vtable = ×pec_vtable; ++num_entries; } if (max_request_message_bytes != NULL) { - method_config->max_request_message_bytes_key = - grpc_mdstr_from_string(GRPC_METHOD_CONFIG_MAX_REQUEST_MESSAGE_BYTES); entries[num_entries].key = method_config->max_request_message_bytes_key; entries[num_entries].value = max_request_message_bytes; entries[num_entries].vtable = &int32_vtable; ++num_entries; } if (max_response_message_bytes != NULL) { - method_config->max_response_message_bytes_key = - grpc_mdstr_from_string(GRPC_METHOD_CONFIG_MAX_RESPONSE_MESSAGE_BYTES); entries[num_entries].key = method_config->max_response_message_bytes_key; entries[num_entries].value = max_response_message_bytes; entries[num_entries].vtable = &int32_vtable; @@ -170,6 +170,7 @@ void grpc_method_config_unref(grpc_method_config* method_config) { GRPC_MDSTR_UNREF(method_config->timeout_key); GRPC_MDSTR_UNREF(method_config->max_request_message_bytes_key); GRPC_MDSTR_UNREF(method_config->max_response_message_bytes_key); + gpr_free(method_config); } } @@ -261,7 +262,7 @@ grpc_method_config* grpc_method_config_table_get_method_config( method_config = grpc_hash_table_get(table, wildcard_path); GRPC_MDSTR_UNREF(wildcard_path); } - return grpc_method_config_ref(method_config); + return method_config; } static void* copy_arg(void* p) { diff --git a/src/core/ext/client_config/method_config.h b/src/core/ext/client_config/method_config.h index e95a5583be2..65b34a768a9 100644 --- a/src/core/ext/client_config/method_config.h +++ b/src/core/ext/client_config/method_config.h @@ -86,7 +86,7 @@ int grpc_method_config_table_cmp(grpc_method_config_table* table1, grpc_method_config_table* table2); /// Returns NULL if the method has no config. -/// Caller owns a reference to result. +/// Caller does NOT own a reference to the result. grpc_method_config* grpc_method_config_table_get_method_config( grpc_method_config_table* table, grpc_mdstr* path); diff --git a/src/core/ext/client_config/resolver_result.c b/src/core/ext/client_config/resolver_result.c index 16d124d2055..63480d152b7 100644 --- a/src/core/ext/client_config/resolver_result.c +++ b/src/core/ext/client_config/resolver_result.c @@ -36,13 +36,8 @@ #include #include -#include "src/core/lib/transport/metadata.h" #include "src/core/lib/channel/channel_args.h" -// -// grpc_resolver_result -// - struct grpc_resolver_result { gpr_refcount refs; char* server_name; diff --git a/src/core/ext/client_config/resolver_result.h b/src/core/ext/client_config/resolver_result.h index 707c8c2cf5c..a7ea7c0f4b8 100644 --- a/src/core/ext/client_config/resolver_result.h +++ b/src/core/ext/client_config/resolver_result.h @@ -48,7 +48,7 @@ /// Results reported from a grpc_resolver. typedef struct grpc_resolver_result grpc_resolver_result; -/// Takes ownership of \a addresses, \a lb_policy_args. +/// Takes ownership of \a addresses and \a lb_policy_args. grpc_resolver_result* grpc_resolver_result_create( const char* server_name, grpc_lb_addresses* addresses, const char* lb_policy_name, grpc_channel_args* lb_policy_args); diff --git a/src/core/lib/channel/channel_args.c b/src/core/lib/channel/channel_args.c index bab6fcd9fa2..2957d2c8188 100644 --- a/src/core/lib/channel/channel_args.c +++ b/src/core/lib/channel/channel_args.c @@ -276,7 +276,9 @@ const grpc_arg *grpc_channel_args_find(const grpc_channel_args *args, const char *name) { if (args != NULL) { for (size_t i = 0; i < args->num_args; ++i) { - if (args->args[i].key == name) return &args->args[i]; + if (strcmp(args->args[i].key, name) == 0) { + return &args->args[i]; + } } } return NULL; diff --git a/src/core/lib/channel/channel_args.h b/src/core/lib/channel/channel_args.h index 38fb4c55d46..a80340c0faf 100644 --- a/src/core/lib/channel/channel_args.h +++ b/src/core/lib/channel/channel_args.h @@ -89,9 +89,7 @@ uint32_t grpc_channel_args_compression_algorithm_get_states( int grpc_channel_args_compare(const grpc_channel_args *a, const grpc_channel_args *b); -/** Returns the value of argument \a name from \a args, or NULL if not found. - Note: \a name is matched using pointer equality, so it must be the - same instance of the string used to create the grpc_arg key. */ +/** Returns the value of argument \a name from \a args, or NULL if not found. */ const grpc_arg *grpc_channel_args_find(const grpc_channel_args *args, const char *name); diff --git a/src/core/lib/transport/hashtable.c b/src/core/lib/transport/hashtable.c index 89e26409693..3e0e0bd6c61 100644 --- a/src/core/lib/transport/hashtable.c +++ b/src/core/lib/transport/hashtable.c @@ -77,7 +77,7 @@ grpc_hash_table* grpc_hash_table_create(size_t num_entries, grpc_hash_table* table = gpr_malloc(sizeof(*table)); memset(table, 0, sizeof(*table)); gpr_ref_init(&table->refs, 1); - // Quadratic chaining gets best performance when the table is no more + // Quadratic probing gets best performance when the table is no more // than half full. table->num_entries = num_entries * 2; const size_t entry_size = sizeof(grpc_hash_table_entry) * table->num_entries; From 72d0b1615f5e1c19acf2b8f1b55339760f63e6ca Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Fri, 30 Sep 2016 09:49:50 -0700 Subject: [PATCH 13/48] Change sockaddr resolver to allow setting method config via URI query params. --- src/core/ext/client_config/method_config.c | 2 +- .../ext/resolver/sockaddr/sockaddr_resolver.c | 83 ++++++++++---- .../resolvers/sockaddr_resolver_test.c | 102 ++++++++++++++++++ 3 files changed, 167 insertions(+), 20 deletions(-) diff --git a/src/core/ext/client_config/method_config.c b/src/core/ext/client_config/method_config.c index 95efe492a95..1135a1c4c46 100644 --- a/src/core/ext/client_config/method_config.c +++ b/src/core/ext/client_config/method_config.c @@ -284,7 +284,7 @@ grpc_arg grpc_method_config_table_create_channel_arg( grpc_arg arg; arg.type = GRPC_ARG_POINTER; arg.key = GRPC_ARG_SERVICE_CONFIG; - arg.value.pointer.p = grpc_method_config_table_ref(table); + arg.value.pointer.p = table; arg.value.pointer.vtable = &arg_vtable; return arg; } diff --git a/src/core/ext/resolver/sockaddr/sockaddr_resolver.c b/src/core/ext/resolver/sockaddr/sockaddr_resolver.c index 74d2015e5c2..98e22f0f63b 100644 --- a/src/core/ext/resolver/sockaddr/sockaddr_resolver.c +++ b/src/core/ext/resolver/sockaddr/sockaddr_resolver.c @@ -33,6 +33,7 @@ #include #include +#include #include #include @@ -40,8 +41,10 @@ #include #include +#include "src/core/ext/client_config/method_config.h" #include "src/core/ext/client_config/parse_address.h" #include "src/core/ext/client_config/resolver_registry.h" +#include "src/core/lib/channel/channel_args.h" #include "src/core/lib/iomgr/resolve_address.h" #include "src/core/lib/iomgr/unix_sockets_posix.h" #include "src/core/lib/support/string.h" @@ -53,6 +56,8 @@ typedef struct { gpr_refcount refs; /** load balancing policy name */ char *lb_policy_name; + /** method config table */ + grpc_method_config_table *method_config_table; /** the addresses that we've 'resolved' */ grpc_lb_addresses *addresses; @@ -120,9 +125,15 @@ static void sockaddr_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx, sockaddr_resolver *r) { if (r->next_completion != NULL && !r->published) { r->published = true; + grpc_channel_args *lb_policy_args = NULL; + if (r->method_config_table != NULL) { + const grpc_arg arg = grpc_method_config_table_create_channel_arg( + r->method_config_table); + lb_policy_args = grpc_channel_args_copy_and_add(NULL /* src */, &arg, 1); + } *r->target_result = grpc_resolver_result_create( "", grpc_lb_addresses_copy(r->addresses, NULL /* user_data_copy */), - r->lb_policy_name, NULL); + r->lb_policy_name, lb_policy_args); grpc_exec_ctx_sched(exec_ctx, r->next_completion, GRPC_ERROR_NONE, NULL); r->next_completion = NULL; } @@ -133,6 +144,7 @@ static void sockaddr_destroy(grpc_exec_ctx *exec_ctx, grpc_resolver *gr) { gpr_mu_destroy(&r->mu); grpc_lb_addresses_destroy(r->addresses, NULL /* user_data_destroy */); gpr_free(r->lb_policy_name); + grpc_method_config_table_unref(r->method_config_table); gpr_free(r); } @@ -164,30 +176,29 @@ static void do_nothing(void *ignored) {} static grpc_resolver *sockaddr_create( grpc_resolver_args *args, const char *default_lb_policy_name, int parse(grpc_uri *uri, struct sockaddr_storage *dst, size_t *len)) { - bool errors_found = false; - sockaddr_resolver *r; - gpr_slice path_slice; - gpr_slice_buffer path_parts; - if (0 != strcmp(args->uri->authority, "")) { gpr_log(GPR_ERROR, "authority based uri's not supported by the %s scheme", args->uri->scheme); return NULL; } - r = gpr_malloc(sizeof(sockaddr_resolver)); + sockaddr_resolver *r = gpr_malloc(sizeof(sockaddr_resolver)); memset(r, 0, sizeof(*r)); + // Initialize LB policy name. r->lb_policy_name = gpr_strdup(grpc_uri_get_query_arg(args->uri, "lb_policy")); + if (r->lb_policy_name == NULL) { + r->lb_policy_name = gpr_strdup(default_lb_policy_name); + } + + // Get lb_enabled arg. const char *lb_enabled_qpart = grpc_uri_get_query_arg(args->uri, "lb_enabled"); - /* anything other than "0" is interpreted as true */ + // Anything other than "0" is interpreted as true. const bool lb_enabled = - (lb_enabled_qpart != NULL && (strcmp("0", lb_enabled_qpart) != 0)); - - if (r->lb_policy_name != NULL && strcmp("grpclb", r->lb_policy_name) == 0 && - !lb_enabled) { + lb_enabled_qpart != NULL && strcmp("0", lb_enabled_qpart) != 0; + if (strcmp("grpclb", r->lb_policy_name) == 0 && !lb_enabled) { /* we want grpclb but the "resolved" addresses aren't LB enabled. Bail * out, as this is meant mostly for tests. */ gpr_log(GPR_ERROR, @@ -196,16 +207,14 @@ static grpc_resolver *sockaddr_create( abort(); } - if (r->lb_policy_name == NULL) { - r->lb_policy_name = gpr_strdup(default_lb_policy_name); - } - - path_slice = + // Construct addresses. + gpr_slice path_slice = gpr_slice_new(args->uri->path, strlen(args->uri->path), do_nothing); + gpr_slice_buffer path_parts; gpr_slice_buffer_init(&path_parts); - gpr_slice_split(path_slice, ",", &path_parts); r->addresses = grpc_lb_addresses_create(path_parts.count); + bool errors_found = false; for (size_t i = 0; i < r->addresses->num_addresses; i++) { grpc_uri ith_uri = *args->uri; char *part_str = gpr_dump_slice(path_parts.slices[i], GPR_DUMP_ASCII); @@ -219,7 +228,6 @@ static grpc_resolver *sockaddr_create( r->addresses->addresses[i].is_balancer = lb_enabled; if (errors_found) break; } - gpr_slice_buffer_destroy(&path_parts); gpr_slice_unref(path_slice); if (errors_found) { @@ -229,6 +237,43 @@ static grpc_resolver *sockaddr_create( return NULL; } + // Construct method config table. + // We only support parameters for a single method. + const char *method_name = grpc_uri_get_query_arg(args->uri, "method_name"); + if (method_name != NULL) { + const char *wait_for_ready_str = + grpc_uri_get_query_arg(args->uri, "wait_for_ready"); + // Anything other than "0" is interpreted as true. + bool wait_for_ready = + wait_for_ready_str != NULL && strcmp("0", wait_for_ready_str) != 0; + const char* timeout_str = + grpc_uri_get_query_arg(args->uri, "timeout_seconds"); + gpr_timespec timeout = { + timeout_str == NULL ? 0 : atoi(timeout_str), 0, GPR_CLOCK_MONOTONIC}; + const char* max_request_message_bytes_str = + grpc_uri_get_query_arg(args->uri, "max_request_message_bytes"); + int32_t max_request_message_bytes = + max_request_message_bytes_str == NULL + ? 0 : atoi(max_request_message_bytes_str); + const char* max_response_message_bytes_str = + grpc_uri_get_query_arg(args->uri, "max_response_message_bytes"); + int32_t max_response_message_bytes = + max_response_message_bytes_str == NULL + ? 0 : atoi(max_response_message_bytes_str); + grpc_method_config *method_config = grpc_method_config_create( + wait_for_ready_str == NULL ? NULL : &wait_for_ready, + timeout_str == NULL ? NULL : &timeout, + max_request_message_bytes_str == NULL + ? NULL : &max_request_message_bytes, + max_response_message_bytes_str == NULL + ? NULL : &max_response_message_bytes); + grpc_method_config_table_entry entry = { + grpc_mdstr_from_string(method_name), method_config}; + r->method_config_table = grpc_method_config_table_create(1, &entry); + GRPC_MDSTR_UNREF(entry.method_name); + grpc_method_config_unref(method_config); + } + gpr_ref_init(&r->refs, 1); gpr_mu_init(&r->mu); grpc_resolver_init(&r->base, &sockaddr_resolver_vtable); diff --git a/test/core/client_config/resolvers/sockaddr_resolver_test.c b/test/core/client_config/resolvers/sockaddr_resolver_test.c index d8430d39c4c..d7dac9848a0 100644 --- a/test/core/client_config/resolvers/sockaddr_resolver_test.c +++ b/test/core/client_config/resolvers/sockaddr_resolver_test.c @@ -33,11 +33,66 @@ #include +#include #include +#include +#include "src/core/ext/client_config/method_config.h" #include "src/core/ext/client_config/resolver_registry.h" +#include "src/core/ext/client_config/resolver_result.h" +#include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/transport/metadata.h" + #include "test/core/util/test_config.h" +typedef struct on_resolution_arg { + const char *expected_method_name; + bool expected_wait_for_ready; + gpr_timespec expected_timeout; + int32_t expected_max_request_message_bytes; + int32_t expected_max_response_message_bytes; + grpc_resolver_result *resolver_result; +} on_resolution_arg; + +void on_resolution_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { + on_resolution_arg *res = arg; + const grpc_channel_args *lb_policy_args = + grpc_resolver_result_get_lb_policy_args(res->resolver_result); + if (res->expected_method_name == NULL) { + GPR_ASSERT(lb_policy_args == NULL); + } else { + const grpc_arg *channel_arg = grpc_channel_args_find( + lb_policy_args, GRPC_ARG_SERVICE_CONFIG); + GPR_ASSERT(channel_arg != NULL); + GPR_ASSERT(channel_arg->type == GRPC_ARG_POINTER); + grpc_method_config_table *method_config_table = + (grpc_method_config_table *)channel_arg->value.pointer.p; + GPR_ASSERT(method_config_table != NULL); + grpc_mdstr *path = grpc_mdstr_from_string(res->expected_method_name); + grpc_method_config *method_config = + grpc_method_config_table_get_method_config(method_config_table, path); + GRPC_MDSTR_UNREF(path); + GPR_ASSERT(method_config != NULL); + bool* wait_for_ready = grpc_method_config_get_wait_for_ready(method_config); + GPR_ASSERT(wait_for_ready != NULL); + GPR_ASSERT(*wait_for_ready == res->expected_wait_for_ready); + gpr_timespec* timeout = grpc_method_config_get_timeout(method_config); + GPR_ASSERT(timeout != NULL); + GPR_ASSERT(gpr_time_cmp(*timeout, res->expected_timeout) == 0); + int32_t* max_request_message_bytes = + grpc_method_config_get_max_request_message_bytes(method_config); + GPR_ASSERT(max_request_message_bytes != NULL); + GPR_ASSERT(*max_request_message_bytes == + res->expected_max_request_message_bytes); + int32_t* max_response_message_bytes = + grpc_method_config_get_max_response_message_bytes(method_config); + GPR_ASSERT(max_response_message_bytes != NULL); + GPR_ASSERT(*max_response_message_bytes == + res->expected_max_response_message_bytes); + } + grpc_resolver_result_unref(exec_ctx, res->resolver_result); +} + static void test_succeeds(grpc_resolver_factory *factory, const char *string) { grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_uri *uri = grpc_uri_parse(string, 0); @@ -50,9 +105,46 @@ static void test_succeeds(grpc_resolver_factory *factory, const char *string) { args.uri = uri; resolver = grpc_resolver_factory_create_resolver(factory, &args); GPR_ASSERT(resolver != NULL); + on_resolution_arg on_res_arg; + memset(&on_res_arg, 0, sizeof(on_res_arg)); + grpc_closure *on_resolution = + grpc_closure_create(on_resolution_cb, &on_res_arg); + grpc_resolver_next(&exec_ctx, resolver, &on_res_arg.resolver_result, + on_resolution); GRPC_RESOLVER_UNREF(&exec_ctx, resolver, "test_succeeds"); + grpc_exec_ctx_finish(&exec_ctx); grpc_uri_destroy(uri); +} + +static void test_succeeds_with_service_config( + grpc_resolver_factory *factory, const char *string, + const char *method_name, bool wait_for_ready, gpr_timespec timeout, + int32_t max_request_message_bytes, int32_t max_response_message_bytes) { + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_uri *uri = grpc_uri_parse(string, 0); + grpc_resolver_args args; + grpc_resolver *resolver; + gpr_log(GPR_DEBUG, "test: '%s' should be valid for '%s'", string, + factory->vtable->scheme); + GPR_ASSERT(uri); + memset(&args, 0, sizeof(args)); + args.uri = uri; + resolver = grpc_resolver_factory_create_resolver(factory, &args); + GPR_ASSERT(resolver != NULL); + on_resolution_arg on_res_arg; + memset(&on_res_arg, 0, sizeof(on_res_arg)); + on_res_arg.expected_method_name = method_name; + on_res_arg.expected_wait_for_ready = wait_for_ready; + on_res_arg.expected_timeout = timeout; + on_res_arg.expected_max_request_message_bytes = max_request_message_bytes; + on_res_arg.expected_max_response_message_bytes = max_response_message_bytes; + grpc_closure *on_resolution = + grpc_closure_create(on_resolution_cb, &on_res_arg); + grpc_resolver_next(&exec_ctx, resolver, &on_res_arg.resolver_result, + on_resolution); + GRPC_RESOLVER_UNREF(&exec_ctx, resolver, "test_succeeds"); grpc_exec_ctx_finish(&exec_ctx); + grpc_uri_destroy(uri); } static void test_fails(grpc_resolver_factory *factory, const char *string) { @@ -93,6 +185,16 @@ int main(int argc, char **argv) { test_fails(ipv6, "ipv6:[::]:123456"); test_fails(ipv6, "ipv6:www.google.com"); + test_succeeds_with_service_config( + ipv4, + "ipv4:127.0.0.1:1234?method_name=/service/method" + "&wait_for_ready=1" + "&timeout_seconds=7" + "&max_request_message_bytes=456" + "&max_response_message_bytes=789", + "/service/method", true /* wait_for_ready */, + (gpr_timespec){7, 0, GPR_CLOCK_MONOTONIC}, 456, 789); + grpc_resolver_factory_unref(ipv4); grpc_resolver_factory_unref(ipv6); grpc_shutdown(); From afa8c1051ec585222e0bb02a63c6c25a4a3b4d3c Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Fri, 30 Sep 2016 10:56:53 -0700 Subject: [PATCH 14/48] clang-format --- include/grpc/impl/codegen/grpc_types.h | 10 +++--- src/core/ext/client_config/client_channel.c | 16 ++++++---- src/core/ext/client_config/method_config.c | 18 ++++------- .../ext/resolver/sockaddr/sockaddr_resolver.c | 32 ++++++++++--------- src/core/lib/channel/message_size_filter.c | 8 ++--- src/core/lib/transport/hashtable.c | 4 +-- src/core/lib/transport/hashtable.h | 2 +- .../resolvers/sockaddr_resolver_test.c | 16 +++++----- 8 files changed, 53 insertions(+), 53 deletions(-) diff --git a/include/grpc/impl/codegen/grpc_types.h b/include/grpc/impl/codegen/grpc_types.h index 43b6a73faac..a3fc683e579 100644 --- a/include/grpc/impl/codegen/grpc_types.h +++ b/include/grpc/impl/codegen/grpc_types.h @@ -263,7 +263,7 @@ typedef enum grpc_call_error { #define GRPC_INITIAL_METADATA_WAIT_FOR_READY (0x00000020u) /** DEPRECATED: for backward compatibility */ #define GRPC_INITIAL_METADATA_IGNORE_CONNECTIVITY \ - GRPC_INITIAL_METADATA_WAIT_FOR_READY + GRPC_INITIAL_METADATA_WAIT_FOR_READY /** Signal that the call is cacheable. GRPC is free to use GET verb */ #define GRPC_INITIAL_METADATA_CACHEABLE_REQUEST (0x00000040u) /** Signal that GRPC_INITIAL_METADATA_WAIT_FOR_READY was explicitly set @@ -271,10 +271,10 @@ typedef enum grpc_call_error { #define GRPC_INITIAL_METADATA_WAIT_FOR_READY_EXPLICITLY_SET (0x00000080u) /** Mask of all valid flags */ -#define GRPC_INITIAL_METADATA_USED_MASK \ - (GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST | \ - GRPC_INITIAL_METADATA_WAIT_FOR_READY | \ - GRPC_INITIAL_METADATA_CACHEABLE_REQUEST | \ +#define GRPC_INITIAL_METADATA_USED_MASK \ + (GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST | \ + GRPC_INITIAL_METADATA_WAIT_FOR_READY | \ + GRPC_INITIAL_METADATA_CACHEABLE_REQUEST | \ GRPC_INITIAL_METADATA_WAIT_FOR_READY_EXPLICITLY_SET) /** A single metadata element */ diff --git a/src/core/ext/client_config/client_channel.c b/src/core/ext/client_config/client_channel.c index 026d3a51b84..00567cc32ae 100644 --- a/src/core/ext/client_config/client_channel.c +++ b/src/core/ext/client_config/client_channel.c @@ -421,8 +421,11 @@ typedef struct client_channel_call_data { grpc_deadline_state deadline_state; gpr_timespec deadline; - enum { WAIT_FOR_READY_UNSET, WAIT_FOR_READY_FALSE, WAIT_FOR_READY_TRUE } - wait_for_ready_from_service_config; + enum { + WAIT_FOR_READY_UNSET, + WAIT_FOR_READY_FALSE, + WAIT_FOR_READY_TRUE + } wait_for_ready_from_service_config; // Request path. grpc_mdstr *path; @@ -798,14 +801,13 @@ static grpc_error *cc_init_call_elem(grpc_exec_ctx *exec_ctx, : grpc_method_config_table_ref(chand->method_config_table); gpr_mu_unlock(&chand->mu); grpc_method_config *method_config = - method_config_table == NULL - ? NULL - : grpc_method_config_table_get_method_config(method_config_table, - args->path); + method_config_table == NULL ? NULL + : grpc_method_config_table_get_method_config( + method_config_table, args->path); grpc_deadline_state_init(exec_ctx, elem, args, method_config); calld->wait_for_ready_from_service_config = WAIT_FOR_READY_UNSET; if (method_config != NULL) { - bool* wait_for_ready = grpc_method_config_get_wait_for_ready(method_config); + bool *wait_for_ready = grpc_method_config_get_wait_for_ready(method_config); if (wait_for_ready != NULL) { calld->wait_for_ready_from_service_config = *wait_for_ready ? WAIT_FOR_READY_TRUE : WAIT_FOR_READY_FALSE; diff --git a/src/core/ext/client_config/method_config.c b/src/core/ext/client_config/method_config.c index 1135a1c4c46..888b32c7f17 100644 --- a/src/core/ext/client_config/method_config.c +++ b/src/core/ext/client_config/method_config.c @@ -78,8 +78,8 @@ static int timespec_cmp(void* v1, void* v2) { return gpr_time_cmp(*(gpr_timespec*)v1, *(gpr_timespec*)v2); } -static grpc_hash_table_vtable timespec_vtable = { - gpr_free, timespec_copy, timespec_cmp}; +static grpc_hash_table_vtable timespec_vtable = {gpr_free, timespec_copy, + timespec_cmp}; // int32 vtable @@ -102,11 +102,11 @@ static grpc_hash_table_vtable int32_vtable = {gpr_free, int32_copy, int32_cmp}; // Hash table keys. #define GRPC_METHOD_CONFIG_WAIT_FOR_READY "grpc.wait_for_ready" // bool -#define GRPC_METHOD_CONFIG_TIMEOUT "grpc.timeout" // gpr_timespec +#define GRPC_METHOD_CONFIG_TIMEOUT "grpc.timeout" // gpr_timespec #define GRPC_METHOD_CONFIG_MAX_REQUEST_MESSAGE_BYTES \ - "grpc.max_request_message_bytes" // int32 + "grpc.max_request_message_bytes" // int32 #define GRPC_METHOD_CONFIG_MAX_RESPONSE_MESSAGE_BYTES \ - "grpc.max_response_message_bytes" // int32 + "grpc.max_response_message_bytes" // int32 struct grpc_method_config { grpc_hash_table* table; @@ -265,13 +265,9 @@ grpc_method_config* grpc_method_config_table_get_method_config( return method_config; } -static void* copy_arg(void* p) { - return grpc_method_config_table_ref(p); -} +static void* copy_arg(void* p) { return grpc_method_config_table_ref(p); } -static void destroy_arg(void* p) { - grpc_method_config_table_unref(p); -} +static void destroy_arg(void* p) { grpc_method_config_table_unref(p); } static int cmp_arg(void* p1, void* p2) { return grpc_method_config_table_cmp(p1, p2); diff --git a/src/core/ext/resolver/sockaddr/sockaddr_resolver.c b/src/core/ext/resolver/sockaddr/sockaddr_resolver.c index 98e22f0f63b..aea57f99122 100644 --- a/src/core/ext/resolver/sockaddr/sockaddr_resolver.c +++ b/src/core/ext/resolver/sockaddr/sockaddr_resolver.c @@ -127,8 +127,8 @@ static void sockaddr_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx, r->published = true; grpc_channel_args *lb_policy_args = NULL; if (r->method_config_table != NULL) { - const grpc_arg arg = grpc_method_config_table_create_channel_arg( - r->method_config_table); + const grpc_arg arg = + grpc_method_config_table_create_channel_arg(r->method_config_table); lb_policy_args = grpc_channel_args_copy_and_add(NULL /* src */, &arg, 1); } *r->target_result = grpc_resolver_result_create( @@ -246,29 +246,31 @@ static grpc_resolver *sockaddr_create( // Anything other than "0" is interpreted as true. bool wait_for_ready = wait_for_ready_str != NULL && strcmp("0", wait_for_ready_str) != 0; - const char* timeout_str = + const char *timeout_str = grpc_uri_get_query_arg(args->uri, "timeout_seconds"); - gpr_timespec timeout = { - timeout_str == NULL ? 0 : atoi(timeout_str), 0, GPR_CLOCK_MONOTONIC}; - const char* max_request_message_bytes_str = + gpr_timespec timeout = {timeout_str == NULL ? 0 : atoi(timeout_str), 0, + GPR_CLOCK_MONOTONIC}; + const char *max_request_message_bytes_str = grpc_uri_get_query_arg(args->uri, "max_request_message_bytes"); int32_t max_request_message_bytes = max_request_message_bytes_str == NULL - ? 0 : atoi(max_request_message_bytes_str); - const char* max_response_message_bytes_str = + ? 0 + : atoi(max_request_message_bytes_str); + const char *max_response_message_bytes_str = grpc_uri_get_query_arg(args->uri, "max_response_message_bytes"); int32_t max_response_message_bytes = max_response_message_bytes_str == NULL - ? 0 : atoi(max_response_message_bytes_str); + ? 0 + : atoi(max_response_message_bytes_str); grpc_method_config *method_config = grpc_method_config_create( wait_for_ready_str == NULL ? NULL : &wait_for_ready, timeout_str == NULL ? NULL : &timeout, - max_request_message_bytes_str == NULL - ? NULL : &max_request_message_bytes, - max_response_message_bytes_str == NULL - ? NULL : &max_response_message_bytes); - grpc_method_config_table_entry entry = { - grpc_mdstr_from_string(method_name), method_config}; + max_request_message_bytes_str == NULL ? NULL + : &max_request_message_bytes, + max_response_message_bytes_str == NULL ? NULL + : &max_response_message_bytes); + grpc_method_config_table_entry entry = {grpc_mdstr_from_string(method_name), + method_config}; r->method_config_table = grpc_method_config_table_create(1, &entry); GRPC_MDSTR_UNREF(entry.method_name); grpc_method_config_unref(method_config); diff --git a/src/core/lib/channel/message_size_filter.c b/src/core/lib/channel/message_size_filter.c index 4efa6f07be3..a54c424e1b9 100644 --- a/src/core/lib/channel/message_size_filter.c +++ b/src/core/lib/channel/message_size_filter.c @@ -38,8 +38,8 @@ #include #include -#include "src/core/lib/channel/channel_args.h" #include "src/core/ext/client_config/method_config.h" +#include "src/core/lib/channel/channel_args.h" #define DEFAULT_MAX_SEND_MESSAGE_LENGTH -1 // Unlimited. // The protobuf library will (by default) start warning at 100 megs. @@ -181,12 +181,12 @@ static void init_channel_elem(grpc_exec_ctx* exec_ctx, } } // Get method config table from channel args. - const grpc_arg *channel_arg = grpc_channel_args_find( - args->channel_args, GRPC_ARG_SERVICE_CONFIG); + const grpc_arg* channel_arg = + grpc_channel_args_find(args->channel_args, GRPC_ARG_SERVICE_CONFIG); if (channel_arg != NULL) { GPR_ASSERT(channel_arg->type == GRPC_ARG_POINTER); chand->method_config_table = grpc_method_config_table_ref( - (grpc_method_config_table *)channel_arg->value.pointer.p); + (grpc_method_config_table*)channel_arg->value.pointer.p); } } diff --git a/src/core/lib/transport/hashtable.c b/src/core/lib/transport/hashtable.c index 3e0e0bd6c61..838fe1026e3 100644 --- a/src/core/lib/transport/hashtable.c +++ b/src/core/lib/transport/hashtable.c @@ -47,8 +47,8 @@ struct grpc_hash_table { // Helper function for insert and get operations that performs quadratic // probing (https://en.wikipedia.org/wiki/Quadratic_probing). -static size_t grpc_hash_table_find_index( - grpc_hash_table* table, grpc_mdstr* key, bool find_empty) { +static size_t grpc_hash_table_find_index(grpc_hash_table* table, + grpc_mdstr* key, bool find_empty) { for (size_t i = 0; i < table->num_entries; ++i) { const size_t idx = (key->hash + i * i) % table->num_entries; if (table->entries[idx].key == NULL) diff --git a/src/core/lib/transport/hashtable.h b/src/core/lib/transport/hashtable.h index 93f0642c172..3ec48dce3a7 100644 --- a/src/core/lib/transport/hashtable.h +++ b/src/core/lib/transport/hashtable.h @@ -58,7 +58,7 @@ typedef struct grpc_hash_table_vtable { typedef struct grpc_hash_table_entry { grpc_mdstr* key; - void* value; /* Must not be NULL. */ + void* value; /* Must not be NULL. */ const grpc_hash_table_vtable* vtable; } grpc_hash_table_entry; diff --git a/test/core/client_config/resolvers/sockaddr_resolver_test.c b/test/core/client_config/resolvers/sockaddr_resolver_test.c index d7dac9848a0..6d475f47971 100644 --- a/test/core/client_config/resolvers/sockaddr_resolver_test.c +++ b/test/core/client_config/resolvers/sockaddr_resolver_test.c @@ -61,8 +61,8 @@ void on_resolution_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { if (res->expected_method_name == NULL) { GPR_ASSERT(lb_policy_args == NULL); } else { - const grpc_arg *channel_arg = grpc_channel_args_find( - lb_policy_args, GRPC_ARG_SERVICE_CONFIG); + const grpc_arg *channel_arg = + grpc_channel_args_find(lb_policy_args, GRPC_ARG_SERVICE_CONFIG); GPR_ASSERT(channel_arg != NULL); GPR_ASSERT(channel_arg->type == GRPC_ARG_POINTER); grpc_method_config_table *method_config_table = @@ -73,18 +73,18 @@ void on_resolution_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { grpc_method_config_table_get_method_config(method_config_table, path); GRPC_MDSTR_UNREF(path); GPR_ASSERT(method_config != NULL); - bool* wait_for_ready = grpc_method_config_get_wait_for_ready(method_config); + bool *wait_for_ready = grpc_method_config_get_wait_for_ready(method_config); GPR_ASSERT(wait_for_ready != NULL); GPR_ASSERT(*wait_for_ready == res->expected_wait_for_ready); - gpr_timespec* timeout = grpc_method_config_get_timeout(method_config); + gpr_timespec *timeout = grpc_method_config_get_timeout(method_config); GPR_ASSERT(timeout != NULL); GPR_ASSERT(gpr_time_cmp(*timeout, res->expected_timeout) == 0); - int32_t* max_request_message_bytes = + int32_t *max_request_message_bytes = grpc_method_config_get_max_request_message_bytes(method_config); GPR_ASSERT(max_request_message_bytes != NULL); GPR_ASSERT(*max_request_message_bytes == res->expected_max_request_message_bytes); - int32_t* max_response_message_bytes = + int32_t *max_response_message_bytes = grpc_method_config_get_max_response_message_bytes(method_config); GPR_ASSERT(max_response_message_bytes != NULL); GPR_ASSERT(*max_response_message_bytes == @@ -117,8 +117,8 @@ static void test_succeeds(grpc_resolver_factory *factory, const char *string) { } static void test_succeeds_with_service_config( - grpc_resolver_factory *factory, const char *string, - const char *method_name, bool wait_for_ready, gpr_timespec timeout, + grpc_resolver_factory *factory, const char *string, const char *method_name, + bool wait_for_ready, gpr_timespec timeout, int32_t max_request_message_bytes, int32_t max_response_message_bytes) { grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_uri *uri = grpc_uri_parse(string, 0); From ec393343eebbd8a32f05e9d90d92d7325d986b9d Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Mon, 3 Oct 2016 13:14:56 -0700 Subject: [PATCH 15/48] Add h2_fake_resolver end2end test fixture. --- Makefile | 56 + src/core/lib/channel/message_size_filter.c | 2 +- test/core/end2end/end2end_tests.h | 4 +- test/core/end2end/fixtures/h2_census.c | 6 +- test/core/end2end/fixtures/h2_compress.c | 4 +- test/core/end2end/fixtures/h2_fake_resolver.c | 128 + test/core/end2end/fixtures/h2_fakesec.c | 4 +- test/core/end2end/fixtures/h2_fd.c | 5 +- test/core/end2end/fixtures/h2_full+pipe.c | 4 +- test/core/end2end/fixtures/h2_full+trace.c | 4 +- test/core/end2end/fixtures/h2_full.c | 4 +- test/core/end2end/fixtures/h2_http_proxy.c | 4 +- .../core/end2end/fixtures/h2_load_reporting.c | 4 +- test/core/end2end/fixtures/h2_oauth2.c | 4 +- test/core/end2end/fixtures/h2_proxy.c | 4 +- .../core/end2end/fixtures/h2_sockpair+trace.c | 4 +- test/core/end2end/fixtures/h2_sockpair.c | 4 +- .../core/end2end/fixtures/h2_sockpair_1byte.c | 4 +- test/core/end2end/fixtures/h2_ssl.c | 4 +- test/core/end2end/fixtures/h2_ssl_cert.c | 4 +- test/core/end2end/fixtures/h2_ssl_proxy.c | 4 +- test/core/end2end/fixtures/h2_uds.c | 4 +- test/core/end2end/gen_build_yaml.py | 1 + test/core/end2end/tests/bad_hostname.c | 2 +- test/core/end2end/tests/binary_metadata.c | 2 +- test/core/end2end/tests/call_creds.c | 2 +- test/core/end2end/tests/cancel_after_accept.c | 2 +- .../end2end/tests/cancel_after_client_done.c | 2 +- test/core/end2end/tests/cancel_after_invoke.c | 2 +- .../core/end2end/tests/cancel_before_invoke.c | 2 +- test/core/end2end/tests/cancel_in_a_vacuum.c | 2 +- test/core/end2end/tests/cancel_with_status.c | 2 +- test/core/end2end/tests/compressed_payload.c | 2 +- test/core/end2end/tests/connectivity.c | 2 +- test/core/end2end/tests/default_host.c | 2 +- test/core/end2end/tests/disappearing_server.c | 2 +- test/core/end2end/tests/empty_batch.c | 2 +- .../end2end/tests/filter_call_init_fails.c | 2 +- test/core/end2end/tests/filter_causes_close.c | 2 +- .../end2end/tests/graceful_server_shutdown.c | 2 +- test/core/end2end/tests/high_initial_seqno.c | 2 +- test/core/end2end/tests/hpack_size.c | 2 +- test/core/end2end/tests/idempotent_request.c | 2 +- .../core/end2end/tests/invoke_large_request.c | 2 +- test/core/end2end/tests/large_metadata.c | 2 +- test/core/end2end/tests/load_reporting_hook.c | 2 +- .../end2end/tests/max_concurrent_streams.c | 2 +- test/core/end2end/tests/max_message_length.c | 2 +- test/core/end2end/tests/negative_deadline.c | 2 +- .../end2end/tests/network_status_change.c | 2 +- test/core/end2end/tests/no_logging.c | 2 +- test/core/end2end/tests/no_op.c | 2 +- test/core/end2end/tests/payload.c | 2 +- test/core/end2end/tests/ping.c | 2 +- test/core/end2end/tests/ping_pong_streaming.c | 2 +- test/core/end2end/tests/registered_call.c | 2 +- test/core/end2end/tests/request_with_flags.c | 2 +- .../core/end2end/tests/request_with_payload.c | 2 +- .../end2end/tests/server_finishes_request.c | 2 +- .../end2end/tests/shutdown_finishes_calls.c | 2 +- .../end2end/tests/shutdown_finishes_tags.c | 2 +- .../end2end/tests/simple_cacheable_request.c | 2 +- .../end2end/tests/simple_delayed_request.c | 2 +- test/core/end2end/tests/simple_metadata.c | 2 +- test/core/end2end/tests/simple_request.c | 2 +- .../end2end/tests/streaming_error_response.c | 2 +- test/core/end2end/tests/trailing_metadata.c | 2 +- tools/run_tests/sources_and_headers.json | 36 + tools/run_tests/tests.json | 5024 ++++++++++++----- vsprojects/buildtests_c.sln | 56 + .../h2_fake_resolver_nosec_test.vcxproj | 191 + ...2_fake_resolver_nosec_test.vcxproj.filters | 24 + .../h2_fake_resolver_test.vcxproj | 202 + .../h2_fake_resolver_test.vcxproj.filters | 24 + 74 files changed, 4291 insertions(+), 1620 deletions(-) create mode 100644 test/core/end2end/fixtures/h2_fake_resolver.c create mode 100644 vsprojects/vcxproj/test/end2end/fixtures/h2_fake_resolver_nosec_test/h2_fake_resolver_nosec_test.vcxproj create mode 100644 vsprojects/vcxproj/test/end2end/fixtures/h2_fake_resolver_nosec_test/h2_fake_resolver_nosec_test.vcxproj.filters create mode 100644 vsprojects/vcxproj/test/end2end/fixtures/h2_fake_resolver_test/h2_fake_resolver_test.vcxproj create mode 100644 vsprojects/vcxproj/test/end2end/fixtures/h2_fake_resolver_test/h2_fake_resolver_test.vcxproj.filters diff --git a/Makefile b/Makefile index 4a35aacd219..53df9cb28d4 100644 --- a/Makefile +++ b/Makefile @@ -1129,6 +1129,7 @@ bad_ssl_cert_server: $(BINDIR)/$(CONFIG)/bad_ssl_cert_server bad_ssl_cert_test: $(BINDIR)/$(CONFIG)/bad_ssl_cert_test h2_census_test: $(BINDIR)/$(CONFIG)/h2_census_test h2_compress_test: $(BINDIR)/$(CONFIG)/h2_compress_test +h2_fake_resolver_test: $(BINDIR)/$(CONFIG)/h2_fake_resolver_test h2_fakesec_test: $(BINDIR)/$(CONFIG)/h2_fakesec_test h2_fd_test: $(BINDIR)/$(CONFIG)/h2_fd_test h2_full_test: $(BINDIR)/$(CONFIG)/h2_full_test @@ -1147,6 +1148,7 @@ h2_ssl_proxy_test: $(BINDIR)/$(CONFIG)/h2_ssl_proxy_test h2_uds_test: $(BINDIR)/$(CONFIG)/h2_uds_test h2_census_nosec_test: $(BINDIR)/$(CONFIG)/h2_census_nosec_test h2_compress_nosec_test: $(BINDIR)/$(CONFIG)/h2_compress_nosec_test +h2_fake_resolver_nosec_test: $(BINDIR)/$(CONFIG)/h2_fake_resolver_nosec_test h2_fd_nosec_test: $(BINDIR)/$(CONFIG)/h2_fd_nosec_test h2_full_nosec_test: $(BINDIR)/$(CONFIG)/h2_full_nosec_test h2_full+pipe_nosec_test: $(BINDIR)/$(CONFIG)/h2_full+pipe_nosec_test @@ -1352,6 +1354,7 @@ buildtests_c: privatelibs_c \ $(BINDIR)/$(CONFIG)/bad_ssl_cert_test \ $(BINDIR)/$(CONFIG)/h2_census_test \ $(BINDIR)/$(CONFIG)/h2_compress_test \ + $(BINDIR)/$(CONFIG)/h2_fake_resolver_test \ $(BINDIR)/$(CONFIG)/h2_fakesec_test \ $(BINDIR)/$(CONFIG)/h2_fd_test \ $(BINDIR)/$(CONFIG)/h2_full_test \ @@ -1370,6 +1373,7 @@ buildtests_c: privatelibs_c \ $(BINDIR)/$(CONFIG)/h2_uds_test \ $(BINDIR)/$(CONFIG)/h2_census_nosec_test \ $(BINDIR)/$(CONFIG)/h2_compress_nosec_test \ + $(BINDIR)/$(CONFIG)/h2_fake_resolver_nosec_test \ $(BINDIR)/$(CONFIG)/h2_fd_nosec_test \ $(BINDIR)/$(CONFIG)/h2_full_nosec_test \ $(BINDIR)/$(CONFIG)/h2_full+pipe_nosec_test \ @@ -14365,6 +14369,38 @@ endif endif +H2_FAKE_RESOLVER_TEST_SRC = \ + test/core/end2end/fixtures/h2_fake_resolver.c \ + +H2_FAKE_RESOLVER_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(H2_FAKE_RESOLVER_TEST_SRC)))) +ifeq ($(NO_SECURE),true) + +# You can't build secure targets if you don't have OpenSSL. + +$(BINDIR)/$(CONFIG)/h2_fake_resolver_test: openssl_dep_error + +else + + + +$(BINDIR)/$(CONFIG)/h2_fake_resolver_test: $(H2_FAKE_RESOLVER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a + $(E) "[LD] Linking $@" + $(Q) mkdir -p `dirname $@` + $(Q) $(LD) $(LDFLAGS) $(H2_FAKE_RESOLVER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.a $(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)/h2_fake_resolver_test + +endif + +$(OBJDIR)/$(CONFIG)/test/core/end2end/fixtures/h2_fake_resolver.o: $(LIBDIR)/$(CONFIG)/libend2end_tests.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a + +deps_h2_fake_resolver_test: $(H2_FAKE_RESOLVER_TEST_OBJS:.o=.dep) + +ifneq ($(NO_SECURE),true) +ifneq ($(NO_DEPS),true) +-include $(H2_FAKE_RESOLVER_TEST_OBJS:.o=.dep) +endif +endif + + H2_FAKESEC_TEST_SRC = \ test/core/end2end/fixtures/h2_fakesec.c \ @@ -14917,6 +14953,26 @@ ifneq ($(NO_DEPS),true) endif +H2_FAKE_RESOLVER_NOSEC_TEST_SRC = \ + test/core/end2end/fixtures/h2_fake_resolver.c \ + +H2_FAKE_RESOLVER_NOSEC_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(H2_FAKE_RESOLVER_NOSEC_TEST_SRC)))) + + +$(BINDIR)/$(CONFIG)/h2_fake_resolver_nosec_test: $(H2_FAKE_RESOLVER_NOSEC_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_nosec_tests.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a + $(E) "[LD] Linking $@" + $(Q) mkdir -p `dirname $@` + $(Q) $(LD) $(LDFLAGS) $(H2_FAKE_RESOLVER_NOSEC_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_nosec_tests.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/h2_fake_resolver_nosec_test + +$(OBJDIR)/$(CONFIG)/test/core/end2end/fixtures/h2_fake_resolver.o: $(LIBDIR)/$(CONFIG)/libend2end_nosec_tests.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a + +deps_h2_fake_resolver_nosec_test: $(H2_FAKE_RESOLVER_NOSEC_TEST_OBJS:.o=.dep) + +ifneq ($(NO_DEPS),true) +-include $(H2_FAKE_RESOLVER_NOSEC_TEST_OBJS:.o=.dep) +endif + + H2_FD_NOSEC_TEST_SRC = \ test/core/end2end/fixtures/h2_fd.c \ diff --git a/src/core/lib/channel/message_size_filter.c b/src/core/lib/channel/message_size_filter.c index a54c424e1b9..8a32b63449d 100644 --- a/src/core/lib/channel/message_size_filter.c +++ b/src/core/lib/channel/message_size_filter.c @@ -86,7 +86,7 @@ static void recv_message_ready(grpc_exec_ctx* exec_ctx, void* user_data, grpc_exec_ctx_sched(exec_ctx, calld->next_recv_message_ready, error, NULL); } -// Start transport op. +// Start transport stream op. static void start_transport_stream_op(grpc_exec_ctx* exec_ctx, grpc_call_element* elem, grpc_transport_stream_op* op) { diff --git a/test/core/end2end/end2end_tests.h b/test/core/end2end/end2end_tests.h index 34af0936cdb..2230027a45e 100644 --- a/test/core/end2end/end2end_tests.h +++ b/test/core/end2end/end2end_tests.h @@ -43,6 +43,7 @@ typedef struct grpc_end2end_test_config grpc_end2end_test_config; #define FEATURE_MASK_SUPPORTS_HOSTNAME_VERIFICATION 2 #define FEATURE_MASK_SUPPORTS_PER_CALL_CREDENTIALS 4 #define FEATURE_MASK_SUPPORTS_REQUEST_PROXYING 8 +#define FEATURE_MASK_SUPPORTS_QUERY_ARGS 16 #define FAIL_AUTH_CHECK_SERVER_ARG_NAME "fail_auth_check" @@ -59,7 +60,8 @@ struct grpc_end2end_test_config { grpc_end2end_test_fixture (*create_fixture)(grpc_channel_args *client_args, grpc_channel_args *server_args); void (*init_client)(grpc_end2end_test_fixture *f, - grpc_channel_args *client_args); + grpc_channel_args *client_args, + const char *query_args); void (*init_server)(grpc_end2end_test_fixture *f, grpc_channel_args *server_args); void (*tear_down_data)(grpc_end2end_test_fixture *f); diff --git a/test/core/end2end/fixtures/h2_census.c b/test/core/end2end/fixtures/h2_census.c index e46b39e476f..36c2d24329c 100644 --- a/test/core/end2end/fixtures/h2_census.c +++ b/test/core/end2end/fixtures/h2_census.c @@ -79,13 +79,15 @@ static grpc_arg make_census_enable_arg(void) { } void chttp2_init_client_fullstack(grpc_end2end_test_fixture *f, - grpc_channel_args *client_args) { + grpc_channel_args *client_args, + const char *query_args) { + GPR_ASSERT(query_args == NULL); fullstack_fixture_data *ffd = f->fixture_data; grpc_arg arg = make_census_enable_arg(); client_args = grpc_channel_args_copy_and_add(client_args, &arg, 1); f->client = grpc_insecure_channel_create(ffd->localaddr, client_args, NULL); - grpc_channel_args_destroy(client_args); GPR_ASSERT(f->client); + grpc_channel_args_destroy(client_args); } void chttp2_init_server_fullstack(grpc_end2end_test_fixture *f, diff --git a/test/core/end2end/fixtures/h2_compress.c b/test/core/end2end/fixtures/h2_compress.c index 8f9b7c9cd9a..0e84588517a 100644 --- a/test/core/end2end/fixtures/h2_compress.c +++ b/test/core/end2end/fixtures/h2_compress.c @@ -75,7 +75,9 @@ static grpc_end2end_test_fixture chttp2_create_fixture_fullstack_compression( } void chttp2_init_client_fullstack_compression(grpc_end2end_test_fixture *f, - grpc_channel_args *client_args) { + grpc_channel_args *client_args, + const char *query_args) { + GPR_ASSERT(query_args == NULL); fullstack_compression_fixture_data *ffd = f->fixture_data; if (ffd->client_args_compression != NULL) { grpc_channel_args_destroy(ffd->client_args_compression); diff --git a/test/core/end2end/fixtures/h2_fake_resolver.c b/test/core/end2end/fixtures/h2_fake_resolver.c new file mode 100644 index 00000000000..89debddb044 --- /dev/null +++ b/test/core/end2end/fixtures/h2_fake_resolver.c @@ -0,0 +1,128 @@ +// +// Copyright 2016, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +#include "test/core/end2end/end2end_tests.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "src/core/ext/client_config/client_channel.h" +#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h" +#include "src/core/lib/channel/connected_channel.h" +#include "src/core/lib/channel/http_server_filter.h" +#include "src/core/lib/surface/channel.h" +#include "src/core/lib/surface/server.h" +#include "test/core/end2end/fake_resolver.h" +#include "test/core/util/port.h" +#include "test/core/util/test_config.h" + +typedef struct fullstack_fixture_data { + char *localaddr; +} fullstack_fixture_data; + +static grpc_end2end_test_fixture chttp2_create_fixture_fullstack( + grpc_channel_args *client_args, grpc_channel_args *server_args) { + grpc_end2end_test_fixture f; + int port = grpc_pick_unused_port_or_die(); + fullstack_fixture_data *ffd = gpr_malloc(sizeof(fullstack_fixture_data)); + memset(&f, 0, sizeof(f)); + + gpr_join_host_port(&ffd->localaddr, "127.0.0.1", port); + + f.fixture_data = ffd; + f.cq = grpc_completion_queue_create(NULL); + + return f; +} + +void chttp2_init_client_fullstack(grpc_end2end_test_fixture *f, + grpc_channel_args *client_args, + const char *query_args) { + fullstack_fixture_data *ffd = f->fixture_data; + char *server_uri; + gpr_asprintf(&server_uri, "test:%s%s%s", ffd->localaddr, + (query_args == NULL ? "" : "?"), + (query_args == NULL ? "" : query_args)); + gpr_log(GPR_INFO, "server_uri: %s", server_uri); + f->client = grpc_insecure_channel_create(server_uri, client_args, NULL); + GPR_ASSERT(f->client); + gpr_free(server_uri); +} + +void chttp2_init_server_fullstack(grpc_end2end_test_fixture *f, + grpc_channel_args *server_args) { + fullstack_fixture_data *ffd = f->fixture_data; + if (f->server) { + grpc_server_destroy(f->server); + } + f->server = grpc_server_create(server_args, NULL); + grpc_server_register_completion_queue(f->server, f->cq, NULL); + GPR_ASSERT(grpc_server_add_insecure_http2_port(f->server, ffd->localaddr)); + grpc_server_start(f->server); +} + +void chttp2_tear_down_fullstack(grpc_end2end_test_fixture *f) { + fullstack_fixture_data *ffd = f->fixture_data; + gpr_free(ffd->localaddr); + gpr_free(ffd); +} + +/* All test configurations */ +static grpc_end2end_test_config configs[] = { + {"chttp2/fullstack", FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION | + FEATURE_MASK_SUPPORTS_QUERY_ARGS, + chttp2_create_fixture_fullstack, chttp2_init_client_fullstack, + chttp2_init_server_fullstack, chttp2_tear_down_fullstack}, +}; + +int main(int argc, char **argv) { + size_t i; + + grpc_test_init(argc, argv); + grpc_end2end_tests_pre_init(); + grpc_fake_resolver_init(); + grpc_init(); + + for (i = 0; i < sizeof(configs) / sizeof(*configs); i++) { + grpc_end2end_tests(argc, argv, configs[i]); + } + + grpc_shutdown(); + + return 0; +} diff --git a/test/core/end2end/fixtures/h2_fakesec.c b/test/core/end2end/fixtures/h2_fakesec.c index 44408b28afa..dbe9011dcfd 100644 --- a/test/core/end2end/fixtures/h2_fakesec.c +++ b/test/core/end2end/fixtures/h2_fakesec.c @@ -105,7 +105,9 @@ void chttp2_tear_down_secure_fullstack(grpc_end2end_test_fixture *f) { } static void chttp2_init_client_fake_secure_fullstack( - grpc_end2end_test_fixture *f, grpc_channel_args *client_args) { + grpc_end2end_test_fixture *f, grpc_channel_args *client_args, + const char *query_args) { + GPR_ASSERT(query_args == NULL); grpc_channel_credentials *fake_ts_creds = grpc_fake_transport_security_credentials_create(); chttp2_init_client_secure_fullstack(f, client_args, fake_ts_creds); diff --git a/test/core/end2end/fixtures/h2_fd.c b/test/core/end2end/fixtures/h2_fd.c index 8561feed703..5a58fe34cd7 100644 --- a/test/core/end2end/fixtures/h2_fd.c +++ b/test/core/end2end/fixtures/h2_fd.c @@ -73,7 +73,10 @@ static grpc_end2end_test_fixture chttp2_create_fixture_socketpair( } static void chttp2_init_client_socketpair(grpc_end2end_test_fixture *f, - grpc_channel_args *client_args) { + grpc_channel_args *client_args, + const char *query_args) { + GPR_ASSERT(query_args == NULL); + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; sp_fixture_data *sfd = f->fixture_data; diff --git a/test/core/end2end/fixtures/h2_full+pipe.c b/test/core/end2end/fixtures/h2_full+pipe.c index e7dfc561a1d..359af1aaf8c 100644 --- a/test/core/end2end/fixtures/h2_full+pipe.c +++ b/test/core/end2end/fixtures/h2_full+pipe.c @@ -71,7 +71,9 @@ static grpc_end2end_test_fixture chttp2_create_fixture_fullstack( } void chttp2_init_client_fullstack(grpc_end2end_test_fixture *f, - grpc_channel_args *client_args) { + grpc_channel_args *client_args, + const char *query_args) { + GPR_ASSERT(query_args == NULL); fullstack_fixture_data *ffd = f->fixture_data; f->client = grpc_insecure_channel_create(ffd->localaddr, client_args, NULL); GPR_ASSERT(f->client); diff --git a/test/core/end2end/fixtures/h2_full+trace.c b/test/core/end2end/fixtures/h2_full+trace.c index c4dc5b9bc17..ac997b05abf 100644 --- a/test/core/end2end/fixtures/h2_full+trace.c +++ b/test/core/end2end/fixtures/h2_full+trace.c @@ -71,7 +71,9 @@ static grpc_end2end_test_fixture chttp2_create_fixture_fullstack( } void chttp2_init_client_fullstack(grpc_end2end_test_fixture *f, - grpc_channel_args *client_args) { + grpc_channel_args *client_args, + const char *query_args) { + GPR_ASSERT(query_args == NULL); fullstack_fixture_data *ffd = f->fixture_data; f->client = grpc_insecure_channel_create(ffd->localaddr, client_args, NULL); GPR_ASSERT(f->client); diff --git a/test/core/end2end/fixtures/h2_full.c b/test/core/end2end/fixtures/h2_full.c index 4a2f17eb910..a72ab3aedd3 100644 --- a/test/core/end2end/fixtures/h2_full.c +++ b/test/core/end2end/fixtures/h2_full.c @@ -70,7 +70,9 @@ static grpc_end2end_test_fixture chttp2_create_fixture_fullstack( } void chttp2_init_client_fullstack(grpc_end2end_test_fixture *f, - grpc_channel_args *client_args) { + grpc_channel_args *client_args, + const char *query_args) { + GPR_ASSERT(query_args == NULL); fullstack_fixture_data *ffd = f->fixture_data; f->client = grpc_insecure_channel_create(ffd->localaddr, client_args, NULL); GPR_ASSERT(f->client); diff --git a/test/core/end2end/fixtures/h2_http_proxy.c b/test/core/end2end/fixtures/h2_http_proxy.c index a675a11f665..f616da9ed5c 100644 --- a/test/core/end2end/fixtures/h2_http_proxy.c +++ b/test/core/end2end/fixtures/h2_http_proxy.c @@ -75,7 +75,9 @@ static grpc_end2end_test_fixture chttp2_create_fixture_fullstack( } void chttp2_init_client_fullstack(grpc_end2end_test_fixture *f, - grpc_channel_args *client_args) { + grpc_channel_args *client_args, + const char *query_args) { + GPR_ASSERT(query_args == NULL); fullstack_fixture_data *ffd = f->fixture_data; char *proxy_uri; gpr_asprintf(&proxy_uri, "http://%s", diff --git a/test/core/end2end/fixtures/h2_load_reporting.c b/test/core/end2end/fixtures/h2_load_reporting.c index f6d3923db94..fc4db27e3ce 100644 --- a/test/core/end2end/fixtures/h2_load_reporting.c +++ b/test/core/end2end/fixtures/h2_load_reporting.c @@ -73,7 +73,9 @@ static grpc_end2end_test_fixture chttp2_create_fixture_load_reporting( } void chttp2_init_client_load_reporting(grpc_end2end_test_fixture *f, - grpc_channel_args *client_args) { + grpc_channel_args *client_args, + const char *query_args) { + GPR_ASSERT(query_args == NULL); load_reporting_fixture_data *ffd = f->fixture_data; f->client = grpc_insecure_channel_create(ffd->localaddr, client_args, NULL); GPR_ASSERT(f->client); diff --git a/test/core/end2end/fixtures/h2_oauth2.c b/test/core/end2end/fixtures/h2_oauth2.c index fc56998cdb4..dd636cfff60 100644 --- a/test/core/end2end/fixtures/h2_oauth2.c +++ b/test/core/end2end/fixtures/h2_oauth2.c @@ -150,7 +150,9 @@ 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_end2end_test_fixture *f, grpc_channel_args *client_args, + const char *query_args) { + GPR_ASSERT(query_args == NULL); grpc_channel_credentials *ssl_creds = grpc_ssl_credentials_create(test_root_cert, NULL, NULL); grpc_call_credentials *oauth2_creds = diff --git a/test/core/end2end/fixtures/h2_proxy.c b/test/core/end2end/fixtures/h2_proxy.c index c7b99863f02..ea1da2abc11 100644 --- a/test/core/end2end/fixtures/h2_proxy.c +++ b/test/core/end2end/fixtures/h2_proxy.c @@ -85,7 +85,9 @@ static grpc_end2end_test_fixture chttp2_create_fixture_fullstack( } void chttp2_init_client_fullstack(grpc_end2end_test_fixture *f, - grpc_channel_args *client_args) { + grpc_channel_args *client_args, + const char *query_args) { + GPR_ASSERT(query_args == NULL); fullstack_fixture_data *ffd = f->fixture_data; f->client = grpc_insecure_channel_create( grpc_end2end_proxy_get_client_target(ffd->proxy), client_args, NULL); diff --git a/test/core/end2end/fixtures/h2_sockpair+trace.c b/test/core/end2end/fixtures/h2_sockpair+trace.c index b8a5257ab2a..1ca11853096 100644 --- a/test/core/end2end/fixtures/h2_sockpair+trace.c +++ b/test/core/end2end/fixtures/h2_sockpair+trace.c @@ -97,7 +97,9 @@ static grpc_end2end_test_fixture chttp2_create_fixture_socketpair( } static void chttp2_init_client_socketpair(grpc_end2end_test_fixture *f, - grpc_channel_args *client_args) { + grpc_channel_args *client_args, + const char *query_args) { + GPR_ASSERT(query_args == NULL); grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_endpoint_pair *sfd = f->fixture_data; grpc_transport *transport; diff --git a/test/core/end2end/fixtures/h2_sockpair.c b/test/core/end2end/fixtures/h2_sockpair.c index a57990d6e73..265491b56dd 100644 --- a/test/core/end2end/fixtures/h2_sockpair.c +++ b/test/core/end2end/fixtures/h2_sockpair.c @@ -96,7 +96,9 @@ static grpc_end2end_test_fixture chttp2_create_fixture_socketpair( } static void chttp2_init_client_socketpair(grpc_end2end_test_fixture *f, - grpc_channel_args *client_args) { + grpc_channel_args *client_args, + const char *query_args) { + GPR_ASSERT(query_args == NULL); grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_endpoint_pair *sfd = f->fixture_data; grpc_transport *transport; diff --git a/test/core/end2end/fixtures/h2_sockpair_1byte.c b/test/core/end2end/fixtures/h2_sockpair_1byte.c index 50aac8045a9..647585d46c2 100644 --- a/test/core/end2end/fixtures/h2_sockpair_1byte.c +++ b/test/core/end2end/fixtures/h2_sockpair_1byte.c @@ -96,7 +96,9 @@ static grpc_end2end_test_fixture chttp2_create_fixture_socketpair( } static void chttp2_init_client_socketpair(grpc_end2end_test_fixture *f, - grpc_channel_args *client_args) { + grpc_channel_args *client_args, + const char *query_args) { + GPR_ASSERT(query_args == NULL); grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_endpoint_pair *sfd = f->fixture_data; grpc_transport *transport; diff --git a/test/core/end2end/fixtures/h2_ssl.c b/test/core/end2end/fixtures/h2_ssl.c index eb28623264a..63282ae0810 100644 --- a/test/core/end2end/fixtures/h2_ssl.c +++ b/test/core/end2end/fixtures/h2_ssl.c @@ -109,7 +109,9 @@ void chttp2_tear_down_secure_fullstack(grpc_end2end_test_fixture *f) { } static void chttp2_init_client_simple_ssl_secure_fullstack( - grpc_end2end_test_fixture *f, grpc_channel_args *client_args) { + grpc_end2end_test_fixture *f, grpc_channel_args *client_args, + const char *query_args) { + GPR_ASSERT(query_args == NULL); grpc_channel_credentials *ssl_creds = grpc_ssl_credentials_create(NULL, NULL, NULL); grpc_arg ssl_name_override = {GRPC_ARG_STRING, diff --git a/test/core/end2end/fixtures/h2_ssl_cert.c b/test/core/end2end/fixtures/h2_ssl_cert.c index ae2604dfb5c..c92464cd8b6 100644 --- a/test/core/end2end/fixtures/h2_ssl_cert.c +++ b/test/core/end2end/fixtures/h2_ssl_cert.c @@ -156,7 +156,9 @@ typedef enum { NONE, SELF_SIGNED, SIGNED, BAD_CERT_PAIR } certtype; #define CLIENT_INIT(cert_type) \ static void CLIENT_INIT_NAME(cert_type)(grpc_end2end_test_fixture * f, \ - grpc_channel_args * client_args) { \ + grpc_channel_args * client_args, \ + const char *query_args) { \ + GPR_ASSERT(query_args == NULL); \ grpc_channel_credentials *ssl_creds = NULL; \ grpc_ssl_pem_key_cert_pair self_signed_client_key_cert_pair = { \ test_self_signed_client_key, test_self_signed_client_cert}; \ diff --git a/test/core/end2end/fixtures/h2_ssl_proxy.c b/test/core/end2end/fixtures/h2_ssl_proxy.c index eeb54b8b88e..7d39fb20558 100644 --- a/test/core/end2end/fixtures/h2_ssl_proxy.c +++ b/test/core/end2end/fixtures/h2_ssl_proxy.c @@ -142,7 +142,9 @@ void chttp2_tear_down_secure_fullstack(grpc_end2end_test_fixture *f) { } static void chttp2_init_client_simple_ssl_secure_fullstack( - grpc_end2end_test_fixture *f, grpc_channel_args *client_args) { + grpc_end2end_test_fixture *f, grpc_channel_args *client_args, + const char *query_args) { + GPR_ASSERT(query_args == NULL); grpc_channel_credentials *ssl_creds = grpc_ssl_credentials_create(NULL, NULL, NULL); grpc_arg ssl_name_override = {GRPC_ARG_STRING, diff --git a/test/core/end2end/fixtures/h2_uds.c b/test/core/end2end/fixtures/h2_uds.c index cffbeaf0453..e280bb8c291 100644 --- a/test/core/end2end/fixtures/h2_uds.c +++ b/test/core/end2end/fixtures/h2_uds.c @@ -76,7 +76,9 @@ static grpc_end2end_test_fixture chttp2_create_fixture_fullstack( } void chttp2_init_client_fullstack(grpc_end2end_test_fixture *f, - grpc_channel_args *client_args) { + grpc_channel_args *client_args, + const char *query_args) { + GPR_ASSERT(query_args == NULL); fullstack_fixture_data *ffd = f->fixture_data; f->client = grpc_insecure_channel_create(ffd->localaddr, client_args, NULL); } diff --git a/test/core/end2end/gen_build_yaml.py b/test/core/end2end/gen_build_yaml.py index 78b37efd372..23b4eda98b6 100755 --- a/test/core/end2end/gen_build_yaml.py +++ b/test/core/end2end/gen_build_yaml.py @@ -55,6 +55,7 @@ END2END_FIXTURES = { 'h2_census': default_unsecure_fixture_options, 'h2_load_reporting': default_unsecure_fixture_options, 'h2_fakesec': default_secure_fixture_options._replace(ci_mac=False), + 'h2_fake_resolver': default_unsecure_fixture_options, 'h2_fd': fd_unsecure_fixture_options, 'h2_full': default_unsecure_fixture_options, 'h2_full+pipe': default_unsecure_fixture_options._replace( diff --git a/test/core/end2end/tests/bad_hostname.c b/test/core/end2end/tests/bad_hostname.c index e0c7ac7c021..85258dd2882 100644 --- a/test/core/end2end/tests/bad_hostname.c +++ b/test/core/end2end/tests/bad_hostname.c @@ -54,7 +54,7 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config, grpc_end2end_test_fixture f; gpr_log(GPR_INFO, "%s/%s", test_name, config.name); f = config.create_fixture(client_args, server_args); - config.init_client(&f, client_args); + config.init_client(&f, client_args, NULL); config.init_server(&f, server_args); return f; } diff --git a/test/core/end2end/tests/binary_metadata.c b/test/core/end2end/tests/binary_metadata.c index 6b105def33c..73b0f17c241 100644 --- a/test/core/end2end/tests/binary_metadata.c +++ b/test/core/end2end/tests/binary_metadata.c @@ -53,7 +53,7 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config, gpr_log(GPR_INFO, "%s/%s", test_name, config.name); f = config.create_fixture(client_args, server_args); config.init_server(&f, server_args); - config.init_client(&f, client_args); + config.init_client(&f, client_args, NULL); return f; } diff --git a/test/core/end2end/tests/call_creds.c b/test/core/end2end/tests/call_creds.c index 981c0fcc8c5..99c5d94e392 100644 --- a/test/core/end2end/tests/call_creds.c +++ b/test/core/end2end/tests/call_creds.c @@ -61,7 +61,7 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config, grpc_end2end_test_fixture f; gpr_log(GPR_INFO, "%s/%s", test_name, config.name); f = config.create_fixture(NULL, NULL); - config.init_client(&f, NULL); + config.init_client(&f, NULL, NULL); if (fail_server_auth_check) { grpc_arg fail_auth_arg = { GRPC_ARG_STRING, FAIL_AUTH_CHECK_SERVER_ARG_NAME, {NULL}}; diff --git a/test/core/end2end/tests/cancel_after_accept.c b/test/core/end2end/tests/cancel_after_accept.c index b4ac3b3249b..8e2c9a0aa4b 100644 --- a/test/core/end2end/tests/cancel_after_accept.c +++ b/test/core/end2end/tests/cancel_after_accept.c @@ -54,7 +54,7 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config, gpr_log(GPR_INFO, "%s/%s", test_name, config.name); f = config.create_fixture(client_args, server_args); config.init_server(&f, server_args); - config.init_client(&f, client_args); + config.init_client(&f, client_args, NULL); return f; } diff --git a/test/core/end2end/tests/cancel_after_client_done.c b/test/core/end2end/tests/cancel_after_client_done.c index 5adc71e2552..f61a404b2de 100644 --- a/test/core/end2end/tests/cancel_after_client_done.c +++ b/test/core/end2end/tests/cancel_after_client_done.c @@ -54,7 +54,7 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config, gpr_log(GPR_INFO, "%s/%s", test_name, config.name); f = config.create_fixture(client_args, server_args); config.init_server(&f, server_args); - config.init_client(&f, client_args); + config.init_client(&f, client_args, NULL); return f; } diff --git a/test/core/end2end/tests/cancel_after_invoke.c b/test/core/end2end/tests/cancel_after_invoke.c index 85d8799f36d..c31582bf2e5 100644 --- a/test/core/end2end/tests/cancel_after_invoke.c +++ b/test/core/end2end/tests/cancel_after_invoke.c @@ -55,7 +55,7 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config, gpr_log(GPR_INFO, "%s/%s/%s", test_name, config.name, mode.name); f = config.create_fixture(client_args, server_args); config.init_server(&f, server_args); - config.init_client(&f, client_args); + config.init_client(&f, client_args, NULL); return f; } diff --git a/test/core/end2end/tests/cancel_before_invoke.c b/test/core/end2end/tests/cancel_before_invoke.c index c57091476e4..5dcd44e7b4c 100644 --- a/test/core/end2end/tests/cancel_before_invoke.c +++ b/test/core/end2end/tests/cancel_before_invoke.c @@ -53,7 +53,7 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config, gpr_log(GPR_INFO, "%s/%s", test_name, config.name); f = config.create_fixture(client_args, server_args); config.init_server(&f, server_args); - config.init_client(&f, client_args); + config.init_client(&f, client_args, NULL); return f; } diff --git a/test/core/end2end/tests/cancel_in_a_vacuum.c b/test/core/end2end/tests/cancel_in_a_vacuum.c index 3b03616b3bb..7f75a92e4a3 100644 --- a/test/core/end2end/tests/cancel_in_a_vacuum.c +++ b/test/core/end2end/tests/cancel_in_a_vacuum.c @@ -54,7 +54,7 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config, gpr_log(GPR_INFO, "%s/%s", test_name, config.name); f = config.create_fixture(client_args, server_args); config.init_server(&f, server_args); - config.init_client(&f, client_args); + config.init_client(&f, client_args, NULL); return f; } diff --git a/test/core/end2end/tests/cancel_with_status.c b/test/core/end2end/tests/cancel_with_status.c index e65390ac4a5..5cf3eb6be65 100644 --- a/test/core/end2end/tests/cancel_with_status.c +++ b/test/core/end2end/tests/cancel_with_status.c @@ -55,7 +55,7 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config, gpr_log(GPR_INFO, "%s/%s", test_name, config.name); f = config.create_fixture(client_args, server_args); config.init_server(&f, server_args); - config.init_client(&f, client_args); + config.init_client(&f, client_args, NULL); return f; } diff --git a/test/core/end2end/tests/compressed_payload.c b/test/core/end2end/tests/compressed_payload.c index 1724da4d0cf..f598a3812b1 100644 --- a/test/core/end2end/tests/compressed_payload.c +++ b/test/core/end2end/tests/compressed_payload.c @@ -60,7 +60,7 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config, gpr_log(GPR_INFO, "%s/%s", test_name, config.name); f = config.create_fixture(client_args, server_args); config.init_server(&f, server_args); - config.init_client(&f, client_args); + config.init_client(&f, client_args, NULL); return f; } diff --git a/test/core/end2end/tests/connectivity.c b/test/core/end2end/tests/connectivity.c index 260297ebd4d..4a991656660 100644 --- a/test/core/end2end/tests/connectivity.c +++ b/test/core/end2end/tests/connectivity.c @@ -68,7 +68,7 @@ static void test_connectivity(grpc_end2end_test_config config) { gpr_thd_options thdopt = gpr_thd_options_default(); gpr_thd_id thdid; - config.init_client(&f, NULL); + config.init_client(&f, NULL, NULL); ce.channel = f.client; ce.cq = f.cq; diff --git a/test/core/end2end/tests/default_host.c b/test/core/end2end/tests/default_host.c index 208e31697e6..5b32b50c03f 100644 --- a/test/core/end2end/tests/default_host.c +++ b/test/core/end2end/tests/default_host.c @@ -54,7 +54,7 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config, grpc_end2end_test_fixture f; gpr_log(GPR_INFO, "%s/%s", test_name, config.name); f = config.create_fixture(client_args, server_args); - config.init_client(&f, client_args); + config.init_client(&f, client_args, NULL); config.init_server(&f, server_args); return f; } diff --git a/test/core/end2end/tests/disappearing_server.c b/test/core/end2end/tests/disappearing_server.c index a0059b9ad59..d8d76f8c386 100644 --- a/test/core/end2end/tests/disappearing_server.c +++ b/test/core/end2end/tests/disappearing_server.c @@ -193,7 +193,7 @@ static void disappearing_server_test(grpc_end2end_test_config config) { gpr_log(GPR_INFO, "%s/%s", "disappearing_server_test", config.name); - config.init_client(&f, NULL); + config.init_client(&f, NULL, NULL); config.init_server(&f, NULL); do_request_and_shutdown_server(&f, cqv); diff --git a/test/core/end2end/tests/empty_batch.c b/test/core/end2end/tests/empty_batch.c index ac53e1839be..bc27b1ac147 100644 --- a/test/core/end2end/tests/empty_batch.c +++ b/test/core/end2end/tests/empty_batch.c @@ -55,7 +55,7 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config, gpr_log(GPR_INFO, "%s/%s", test_name, config.name); f = config.create_fixture(client_args, server_args); config.init_server(&f, server_args); - config.init_client(&f, client_args); + config.init_client(&f, client_args, NULL); return f; } diff --git a/test/core/end2end/tests/filter_call_init_fails.c b/test/core/end2end/tests/filter_call_init_fails.c index a70f50af988..0e5692f4c9f 100644 --- a/test/core/end2end/tests/filter_call_init_fails.c +++ b/test/core/end2end/tests/filter_call_init_fails.c @@ -61,7 +61,7 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config, gpr_log(GPR_INFO, "%s/%s", test_name, config.name); f = config.create_fixture(client_args, server_args); config.init_server(&f, server_args); - config.init_client(&f, client_args); + config.init_client(&f, client_args, NULL); return f; } diff --git a/test/core/end2end/tests/filter_causes_close.c b/test/core/end2end/tests/filter_causes_close.c index cdf868377ae..adc1e3c4082 100644 --- a/test/core/end2end/tests/filter_causes_close.c +++ b/test/core/end2end/tests/filter_causes_close.c @@ -58,7 +58,7 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config, gpr_log(GPR_INFO, "%s/%s", test_name, config.name); f = config.create_fixture(client_args, server_args); config.init_server(&f, server_args); - config.init_client(&f, client_args); + config.init_client(&f, client_args, NULL); return f; } diff --git a/test/core/end2end/tests/graceful_server_shutdown.c b/test/core/end2end/tests/graceful_server_shutdown.c index 29347a068ae..e098a63f8b4 100644 --- a/test/core/end2end/tests/graceful_server_shutdown.c +++ b/test/core/end2end/tests/graceful_server_shutdown.c @@ -53,7 +53,7 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config, gpr_log(GPR_INFO, "%s/%s", test_name, config.name); f = config.create_fixture(client_args, server_args); config.init_server(&f, server_args); - config.init_client(&f, client_args); + config.init_client(&f, client_args, NULL); return f; } diff --git a/test/core/end2end/tests/high_initial_seqno.c b/test/core/end2end/tests/high_initial_seqno.c index dab527005cf..193706b8cf7 100644 --- a/test/core/end2end/tests/high_initial_seqno.c +++ b/test/core/end2end/tests/high_initial_seqno.c @@ -57,7 +57,7 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config, gpr_log(GPR_INFO, "%s/%s", test_name, config.name); f = config.create_fixture(client_args, server_args); config.init_server(&f, server_args); - config.init_client(&f, client_args); + config.init_client(&f, client_args, NULL); return f; } diff --git a/test/core/end2end/tests/hpack_size.c b/test/core/end2end/tests/hpack_size.c index fb00ae4eaaa..78afdb5594e 100644 --- a/test/core/end2end/tests/hpack_size.c +++ b/test/core/end2end/tests/hpack_size.c @@ -197,7 +197,7 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config, gpr_log(GPR_INFO, "%s/%s", test_name, config.name); f = config.create_fixture(client_args, server_args); config.init_server(&f, server_args); - config.init_client(&f, client_args); + config.init_client(&f, client_args, NULL); return f; } diff --git a/test/core/end2end/tests/idempotent_request.c b/test/core/end2end/tests/idempotent_request.c index 65f6dd08c5a..b53e00386ba 100644 --- a/test/core/end2end/tests/idempotent_request.c +++ b/test/core/end2end/tests/idempotent_request.c @@ -55,7 +55,7 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config, gpr_log(GPR_INFO, "%s/%s", test_name, config.name); f = config.create_fixture(client_args, server_args); config.init_server(&f, server_args); - config.init_client(&f, client_args); + config.init_client(&f, client_args, NULL); return f; } diff --git a/test/core/end2end/tests/invoke_large_request.c b/test/core/end2end/tests/invoke_large_request.c index 1df237cb6c4..3820504e11d 100644 --- a/test/core/end2end/tests/invoke_large_request.c +++ b/test/core/end2end/tests/invoke_large_request.c @@ -54,7 +54,7 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config, gpr_log(GPR_INFO, "%s/%s", test_name, config.name); f = config.create_fixture(client_args, server_args); config.init_server(&f, server_args); - config.init_client(&f, client_args); + config.init_client(&f, client_args, NULL); return f; } diff --git a/test/core/end2end/tests/large_metadata.c b/test/core/end2end/tests/large_metadata.c index eb174a2dbb7..6107836b125 100644 --- a/test/core/end2end/tests/large_metadata.c +++ b/test/core/end2end/tests/large_metadata.c @@ -53,7 +53,7 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config, gpr_log(GPR_INFO, "%s/%s", test_name, config.name); f = config.create_fixture(client_args, server_args); config.init_server(&f, server_args); - config.init_client(&f, client_args); + config.init_client(&f, client_args, NULL); return f; } diff --git a/test/core/end2end/tests/load_reporting_hook.c b/test/core/end2end/tests/load_reporting_hook.c index 59d054cf877..9fdaa6dfcf4 100644 --- a/test/core/end2end/tests/load_reporting_hook.c +++ b/test/core/end2end/tests/load_reporting_hook.c @@ -78,7 +78,7 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config, f = config.create_fixture(client_args, server_args); config.init_server(&f, server_args); - config.init_client(&f, client_args); + config.init_client(&f, client_args, NULL); return f; } diff --git a/test/core/end2end/tests/max_concurrent_streams.c b/test/core/end2end/tests/max_concurrent_streams.c index 65fa9468387..6c7bf9f5316 100644 --- a/test/core/end2end/tests/max_concurrent_streams.c +++ b/test/core/end2end/tests/max_concurrent_streams.c @@ -53,7 +53,7 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config, gpr_log(GPR_INFO, "%s/%s", test_name, config.name); f = config.create_fixture(client_args, server_args); config.init_server(&f, server_args); - config.init_client(&f, client_args); + config.init_client(&f, client_args, NULL); return f; } diff --git a/test/core/end2end/tests/max_message_length.c b/test/core/end2end/tests/max_message_length.c index cdca3e67487..72e28fb0329 100644 --- a/test/core/end2end/tests/max_message_length.c +++ b/test/core/end2end/tests/max_message_length.c @@ -56,7 +56,7 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config, // proxy, only on the backend server. f = config.create_fixture(NULL, NULL); config.init_server(&f, server_args); - config.init_client(&f, client_args); + config.init_client(&f, client_args, NULL); return f; } diff --git a/test/core/end2end/tests/negative_deadline.c b/test/core/end2end/tests/negative_deadline.c index c999ac116aa..12c6a0f2bd8 100644 --- a/test/core/end2end/tests/negative_deadline.c +++ b/test/core/end2end/tests/negative_deadline.c @@ -55,7 +55,7 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config, gpr_log(GPR_INFO, "%s/%s", test_name, config.name); f = config.create_fixture(client_args, server_args); config.init_server(&f, server_args); - config.init_client(&f, client_args); + config.init_client(&f, client_args, NULL); return f; } diff --git a/test/core/end2end/tests/network_status_change.c b/test/core/end2end/tests/network_status_change.c index 1d4b6dbb18f..8d6b8f87840 100644 --- a/test/core/end2end/tests/network_status_change.c +++ b/test/core/end2end/tests/network_status_change.c @@ -56,7 +56,7 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config, gpr_log(GPR_INFO, "%s/%s", test_name, config.name); f = config.create_fixture(client_args, server_args); config.init_server(&f, server_args); - config.init_client(&f, client_args); + config.init_client(&f, client_args, NULL); return f; } diff --git a/test/core/end2end/tests/no_logging.c b/test/core/end2end/tests/no_logging.c index 430bfdc7974..f512c1cca8d 100644 --- a/test/core/end2end/tests/no_logging.c +++ b/test/core/end2end/tests/no_logging.c @@ -83,7 +83,7 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config, gpr_log(GPR_INFO, "%s/%s", test_name, config.name); f = config.create_fixture(client_args, server_args); config.init_server(&f, server_args); - config.init_client(&f, client_args); + config.init_client(&f, client_args, NULL); return f; } diff --git a/test/core/end2end/tests/no_op.c b/test/core/end2end/tests/no_op.c index 8b29c219dcf..a1c61cb8d19 100644 --- a/test/core/end2end/tests/no_op.c +++ b/test/core/end2end/tests/no_op.c @@ -53,7 +53,7 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config, gpr_log(GPR_INFO, "%s/%s", test_name, config.name); f = config.create_fixture(client_args, server_args); config.init_server(&f, server_args); - config.init_client(&f, client_args); + config.init_client(&f, client_args, NULL); return f; } diff --git a/test/core/end2end/tests/payload.c b/test/core/end2end/tests/payload.c index c71704ff61f..c1db2744760 100644 --- a/test/core/end2end/tests/payload.c +++ b/test/core/end2end/tests/payload.c @@ -53,7 +53,7 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config, gpr_log(GPR_INFO, "%s/%s", test_name, config.name); f = config.create_fixture(client_args, server_args); config.init_server(&f, server_args); - config.init_client(&f, client_args); + config.init_client(&f, client_args, NULL); return f; } diff --git a/test/core/end2end/tests/ping.c b/test/core/end2end/tests/ping.c index 5e5169dedce..f7e119cc2f2 100644 --- a/test/core/end2end/tests/ping.c +++ b/test/core/end2end/tests/ping.c @@ -48,7 +48,7 @@ static void test_ping(grpc_end2end_test_config config) { grpc_connectivity_state state = GRPC_CHANNEL_IDLE; int i; - config.init_client(&f, NULL); + config.init_client(&f, NULL, NULL); config.init_server(&f, NULL); grpc_channel_ping(f.client, f.cq, tag(0), NULL); diff --git a/test/core/end2end/tests/ping_pong_streaming.c b/test/core/end2end/tests/ping_pong_streaming.c index 7e360c415b1..30ea80043be 100644 --- a/test/core/end2end/tests/ping_pong_streaming.c +++ b/test/core/end2end/tests/ping_pong_streaming.c @@ -53,7 +53,7 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config, gpr_log(GPR_INFO, "%s/%s", test_name, config.name); f = config.create_fixture(client_args, server_args); config.init_server(&f, server_args); - config.init_client(&f, client_args); + config.init_client(&f, client_args, NULL); return f; } diff --git a/test/core/end2end/tests/registered_call.c b/test/core/end2end/tests/registered_call.c index 9b2b42b5583..4c094e1b8b4 100644 --- a/test/core/end2end/tests/registered_call.c +++ b/test/core/end2end/tests/registered_call.c @@ -55,7 +55,7 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config, gpr_log(GPR_INFO, "%s/%s", test_name, config.name); f = config.create_fixture(client_args, server_args); config.init_server(&f, server_args); - config.init_client(&f, client_args); + config.init_client(&f, client_args, NULL); return f; } diff --git a/test/core/end2end/tests/request_with_flags.c b/test/core/end2end/tests/request_with_flags.c index 25150e6f2d6..69ad69af66a 100644 --- a/test/core/end2end/tests/request_with_flags.c +++ b/test/core/end2end/tests/request_with_flags.c @@ -54,7 +54,7 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config, gpr_log(GPR_INFO, "%s/%s", test_name, config.name); f = config.create_fixture(client_args, server_args); config.init_server(&f, server_args); - config.init_client(&f, client_args); + config.init_client(&f, client_args, NULL); return f; } diff --git a/test/core/end2end/tests/request_with_payload.c b/test/core/end2end/tests/request_with_payload.c index 67208c050c1..56ff83cdb4a 100644 --- a/test/core/end2end/tests/request_with_payload.c +++ b/test/core/end2end/tests/request_with_payload.c @@ -53,7 +53,7 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config, gpr_log(GPR_INFO, "%s/%s", test_name, config.name); f = config.create_fixture(client_args, server_args); config.init_server(&f, server_args); - config.init_client(&f, client_args); + config.init_client(&f, client_args, NULL); return f; } diff --git a/test/core/end2end/tests/server_finishes_request.c b/test/core/end2end/tests/server_finishes_request.c index 7fb9025aa38..c23b7581f48 100644 --- a/test/core/end2end/tests/server_finishes_request.c +++ b/test/core/end2end/tests/server_finishes_request.c @@ -55,7 +55,7 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config, gpr_log(GPR_INFO, "%s/%s", test_name, config.name); f = config.create_fixture(client_args, server_args); config.init_server(&f, server_args); - config.init_client(&f, client_args); + config.init_client(&f, client_args, NULL); return f; } diff --git a/test/core/end2end/tests/shutdown_finishes_calls.c b/test/core/end2end/tests/shutdown_finishes_calls.c index dff2e6f2809..a21a63ad787 100644 --- a/test/core/end2end/tests/shutdown_finishes_calls.c +++ b/test/core/end2end/tests/shutdown_finishes_calls.c @@ -53,7 +53,7 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config, gpr_log(GPR_INFO, "%s/%s", test_name, config.name); f = config.create_fixture(client_args, server_args); config.init_server(&f, server_args); - config.init_client(&f, client_args); + config.init_client(&f, client_args, NULL); return f; } diff --git a/test/core/end2end/tests/shutdown_finishes_tags.c b/test/core/end2end/tests/shutdown_finishes_tags.c index 1d110a74eac..aca7c55b9f1 100644 --- a/test/core/end2end/tests/shutdown_finishes_tags.c +++ b/test/core/end2end/tests/shutdown_finishes_tags.c @@ -53,7 +53,7 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config, gpr_log(GPR_INFO, "%s/%s", test_name, config.name); f = config.create_fixture(client_args, server_args); config.init_server(&f, server_args); - config.init_client(&f, client_args); + config.init_client(&f, client_args, NULL); return f; } diff --git a/test/core/end2end/tests/simple_cacheable_request.c b/test/core/end2end/tests/simple_cacheable_request.c index b52eb19315e..29ba41bd8bf 100644 --- a/test/core/end2end/tests/simple_cacheable_request.c +++ b/test/core/end2end/tests/simple_cacheable_request.c @@ -55,7 +55,7 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config, gpr_log(GPR_INFO, "%s/%s", test_name, config.name); f = config.create_fixture(client_args, server_args); config.init_server(&f, server_args); - config.init_client(&f, client_args); + config.init_client(&f, client_args, NULL); return f; } diff --git a/test/core/end2end/tests/simple_delayed_request.c b/test/core/end2end/tests/simple_delayed_request.c index 74f1232d786..e1a1b8c585e 100644 --- a/test/core/end2end/tests/simple_delayed_request.c +++ b/test/core/end2end/tests/simple_delayed_request.c @@ -104,7 +104,7 @@ static void simple_delayed_request_body(grpc_end2end_test_config config, size_t details_capacity = 0; int was_cancelled = 2; - config.init_client(f, client_args); + config.init_client(f, client_args, NULL); c = grpc_channel_create_call(f->client, NULL, GRPC_PROPAGATE_DEFAULTS, f->cq, "/foo", "foo.test.google.fr", deadline, NULL); diff --git a/test/core/end2end/tests/simple_metadata.c b/test/core/end2end/tests/simple_metadata.c index 13c77c033e0..304af9c3fa0 100644 --- a/test/core/end2end/tests/simple_metadata.c +++ b/test/core/end2end/tests/simple_metadata.c @@ -53,7 +53,7 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config, gpr_log(GPR_INFO, "%s/%s", test_name, config.name); f = config.create_fixture(client_args, server_args); config.init_server(&f, server_args); - config.init_client(&f, client_args); + config.init_client(&f, client_args, NULL); return f; } diff --git a/test/core/end2end/tests/simple_request.c b/test/core/end2end/tests/simple_request.c index ed7b850808a..65a3710c143 100644 --- a/test/core/end2end/tests/simple_request.c +++ b/test/core/end2end/tests/simple_request.c @@ -55,7 +55,7 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config, gpr_log(GPR_INFO, "%s/%s", test_name, config.name); f = config.create_fixture(client_args, server_args); config.init_server(&f, server_args); - config.init_client(&f, client_args); + config.init_client(&f, client_args, NULL); return f; } diff --git a/test/core/end2end/tests/streaming_error_response.c b/test/core/end2end/tests/streaming_error_response.c index 8285468321c..fe63c6f7bb8 100644 --- a/test/core/end2end/tests/streaming_error_response.c +++ b/test/core/end2end/tests/streaming_error_response.c @@ -55,7 +55,7 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config, request_status_early ? "true" : "false"); f = config.create_fixture(client_args, server_args); config.init_server(&f, server_args); - config.init_client(&f, client_args); + config.init_client(&f, client_args, NULL); return f; } diff --git a/test/core/end2end/tests/trailing_metadata.c b/test/core/end2end/tests/trailing_metadata.c index d7093ae7239..e6bfc7c9f10 100644 --- a/test/core/end2end/tests/trailing_metadata.c +++ b/test/core/end2end/tests/trailing_metadata.c @@ -53,7 +53,7 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config, gpr_log(GPR_INFO, "%s/%s", test_name, config.name); f = config.create_fixture(client_args, server_args); config.init_server(&f, server_args); - config.init_client(&f, client_args); + config.init_client(&f, client_args, NULL); return f; } diff --git a/tools/run_tests/sources_and_headers.json b/tools/run_tests/sources_and_headers.json index 18d27220cc9..125e7cbe240 100644 --- a/tools/run_tests/sources_and_headers.json +++ b/tools/run_tests/sources_and_headers.json @@ -3897,6 +3897,24 @@ "third_party": false, "type": "target" }, + { + "deps": [ + "end2end_tests", + "gpr", + "gpr_test_util", + "grpc", + "grpc_test_util" + ], + "headers": [], + "is_filegroup": false, + "language": "c", + "name": "h2_fake_resolver_test", + "src": [ + "test/core/end2end/fixtures/h2_fake_resolver.c" + ], + "third_party": false, + "type": "target" + }, { "deps": [ "end2end_tests", @@ -4221,6 +4239,24 @@ "third_party": false, "type": "target" }, + { + "deps": [ + "end2end_nosec_tests", + "gpr", + "gpr_test_util", + "grpc_test_util_unsecure", + "grpc_unsecure" + ], + "headers": [], + "is_filegroup": false, + "language": "c", + "name": "h2_fake_resolver_nosec_test", + "src": [ + "test/core/end2end/fixtures/h2_fake_resolver.c" + ], + "third_party": false, + "type": "target" + }, { "deps": [ "end2end_nosec_tests", diff --git a/tools/run_tests/tests.json b/tools/run_tests/tests.json index 355fea5d5f4..eaa892c421f 100644 --- a/tools/run_tests/tests.json +++ b/tools/run_tests/tests.json @@ -6460,13 +6460,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fakesec_test", + "name": "h2_fake_resolver_test", "platforms": [ "windows", "linux", @@ -6481,13 +6482,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fakesec_test", + "name": "h2_fake_resolver_test", "platforms": [ "windows", "linux", @@ -6502,13 +6504,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fakesec_test", + "name": "h2_fake_resolver_test", "platforms": [ "windows", "linux", @@ -6523,13 +6526,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fakesec_test", + "name": "h2_fake_resolver_test", "platforms": [ "windows", "linux", @@ -6544,13 +6548,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fakesec_test", + "name": "h2_fake_resolver_test", "platforms": [ "windows", "linux", @@ -6565,13 +6570,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fakesec_test", + "name": "h2_fake_resolver_test", "platforms": [ "windows", "linux", @@ -6586,13 +6592,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fakesec_test", + "name": "h2_fake_resolver_test", "platforms": [ "windows", "linux", @@ -6607,13 +6614,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fakesec_test", + "name": "h2_fake_resolver_test", "platforms": [ "windows", "linux", @@ -6628,13 +6636,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fakesec_test", + "name": "h2_fake_resolver_test", "platforms": [ "windows", "linux", @@ -6649,13 +6658,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fakesec_test", + "name": "h2_fake_resolver_test", "platforms": [ "windows", "linux", @@ -6670,13 +6680,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fakesec_test", + "name": "h2_fake_resolver_test", "platforms": [ "windows", "linux", @@ -6691,13 +6702,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fakesec_test", + "name": "h2_fake_resolver_test", "platforms": [ "windows", "linux", @@ -6712,13 +6724,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fakesec_test", + "name": "h2_fake_resolver_test", "platforms": [ "windows", "linux", @@ -6733,13 +6746,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fakesec_test", + "name": "h2_fake_resolver_test", "platforms": [ "windows", "linux", @@ -6754,13 +6768,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fakesec_test", + "name": "h2_fake_resolver_test", "platforms": [ "windows", "linux", @@ -6775,13 +6790,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fakesec_test", + "name": "h2_fake_resolver_test", "platforms": [ "windows", "linux", @@ -6796,13 +6812,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fakesec_test", + "name": "h2_fake_resolver_test", "platforms": [ "windows", "linux", @@ -6817,13 +6834,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fakesec_test", + "name": "h2_fake_resolver_test", "platforms": [ "windows", "linux", @@ -6838,13 +6856,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fakesec_test", + "name": "h2_fake_resolver_test", "platforms": [ "windows", "linux", @@ -6859,13 +6878,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fakesec_test", + "name": "h2_fake_resolver_test", "platforms": [ "windows", "linux", @@ -6880,13 +6900,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fakesec_test", + "name": "h2_fake_resolver_test", "platforms": [ "windows", "linux", @@ -6901,13 +6922,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fakesec_test", + "name": "h2_fake_resolver_test", "platforms": [ "windows", "linux", @@ -6922,13 +6944,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fakesec_test", + "name": "h2_fake_resolver_test", "platforms": [ "windows", "linux", @@ -6943,13 +6966,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fakesec_test", + "name": "h2_fake_resolver_test", "platforms": [ "windows", "linux", @@ -6964,13 +6988,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fakesec_test", + "name": "h2_fake_resolver_test", "platforms": [ "windows", "linux", @@ -6985,13 +7010,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fakesec_test", + "name": "h2_fake_resolver_test", "platforms": [ "windows", "linux", @@ -7006,13 +7032,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fakesec_test", + "name": "h2_fake_resolver_test", "platforms": [ "windows", "linux", @@ -7027,13 +7054,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fakesec_test", + "name": "h2_fake_resolver_test", "platforms": [ "windows", "linux", @@ -7048,13 +7076,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fakesec_test", + "name": "h2_fake_resolver_test", "platforms": [ "windows", "linux", @@ -7069,13 +7098,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fakesec_test", + "name": "h2_fake_resolver_test", "platforms": [ "windows", "linux", @@ -7090,13 +7120,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fakesec_test", + "name": "h2_fake_resolver_test", "platforms": [ "windows", "linux", @@ -7111,13 +7142,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fakesec_test", + "name": "h2_fake_resolver_test", "platforms": [ "windows", "linux", @@ -7132,13 +7164,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fakesec_test", + "name": "h2_fake_resolver_test", "platforms": [ "windows", "linux", @@ -7153,13 +7186,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fakesec_test", + "name": "h2_fake_resolver_test", "platforms": [ "windows", "linux", @@ -7174,13 +7208,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fakesec_test", + "name": "h2_fake_resolver_test", "platforms": [ "windows", "linux", @@ -7195,13 +7230,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fakesec_test", + "name": "h2_fake_resolver_test", "platforms": [ "windows", "linux", @@ -7216,13 +7252,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fakesec_test", + "name": "h2_fake_resolver_test", "platforms": [ "windows", "linux", @@ -7237,13 +7274,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fakesec_test", + "name": "h2_fake_resolver_test", "platforms": [ "windows", "linux", @@ -7258,13 +7296,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fakesec_test", + "name": "h2_fake_resolver_test", "platforms": [ "windows", "linux", @@ -7279,13 +7318,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fakesec_test", + "name": "h2_fake_resolver_test", "platforms": [ "windows", "linux", @@ -7300,13 +7340,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fakesec_test", + "name": "h2_fake_resolver_test", "platforms": [ "windows", "linux", @@ -7321,13 +7362,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fakesec_test", + "name": "h2_fake_resolver_test", "platforms": [ "windows", "linux", @@ -7342,13 +7384,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fakesec_test", + "name": "h2_fake_resolver_test", "platforms": [ "windows", "linux", @@ -7363,13 +7406,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fakesec_test", + "name": "h2_fake_resolver_test", "platforms": [ "windows", "linux", @@ -7382,16 +7426,17 @@ "bad_hostname" ], "ci_platforms": [ + "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fd_test", + "name": "h2_fakesec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -7402,16 +7447,17 @@ "binary_metadata" ], "ci_platforms": [ + "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fd_test", + "name": "h2_fakesec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -7422,16 +7468,17 @@ "call_creds" ], "ci_platforms": [ + "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fd_test", + "name": "h2_fakesec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -7442,16 +7489,17 @@ "cancel_after_accept" ], "ci_platforms": [ + "windows", "linux", - "mac", "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fd_test", + "name": "h2_fakesec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -7462,16 +7510,17 @@ "cancel_after_client_done" ], "ci_platforms": [ + "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fd_test", + "name": "h2_fakesec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -7482,16 +7531,17 @@ "cancel_after_invoke" ], "ci_platforms": [ + "windows", "linux", - "mac", "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fd_test", + "name": "h2_fakesec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -7502,16 +7552,17 @@ "cancel_before_invoke" ], "ci_platforms": [ + "windows", "linux", - "mac", "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fd_test", + "name": "h2_fakesec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -7522,16 +7573,17 @@ "cancel_in_a_vacuum" ], "ci_platforms": [ + "windows", "linux", - "mac", "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fd_test", + "name": "h2_fakesec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -7542,16 +7594,17 @@ "cancel_with_status" ], "ci_platforms": [ + "windows", "linux", - "mac", "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fd_test", + "name": "h2_fakesec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -7562,16 +7615,17 @@ "compressed_payload" ], "ci_platforms": [ + "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fd_test", + "name": "h2_fakesec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -7579,19 +7633,20 @@ }, { "args": [ - "empty_batch" + "connectivity" ], "ci_platforms": [ + "windows", "linux", - "mac", "posix" ], - "cpu_cost": 1.0, + "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fd_test", + "name": "h2_fakesec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -7599,19 +7654,20 @@ }, { "args": [ - "filter_call_init_fails" + "default_host" ], "ci_platforms": [ + "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fd_test", + "name": "h2_fakesec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -7619,19 +7675,20 @@ }, { "args": [ - "filter_causes_close" + "disappearing_server" ], "ci_platforms": [ + "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fd_test", + "name": "h2_fakesec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -7639,19 +7696,20 @@ }, { "args": [ - "graceful_server_shutdown" + "empty_batch" ], "ci_platforms": [ + "windows", "linux", - "mac", "posix" ], - "cpu_cost": 0.1, + "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fd_test", + "name": "h2_fakesec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -7659,19 +7717,20 @@ }, { "args": [ - "high_initial_seqno" + "filter_call_init_fails" ], "ci_platforms": [ + "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fd_test", + "name": "h2_fakesec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -7679,19 +7738,20 @@ }, { "args": [ - "hpack_size" + "filter_causes_close" ], "ci_platforms": [ + "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fd_test", + "name": "h2_fakesec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -7699,19 +7759,20 @@ }, { "args": [ - "idempotent_request" + "graceful_server_shutdown" ], "ci_platforms": [ + "windows", "linux", - "mac", "posix" ], - "cpu_cost": 1.0, + "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fd_test", + "name": "h2_fakesec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -7719,19 +7780,20 @@ }, { "args": [ - "invoke_large_request" + "high_initial_seqno" ], "ci_platforms": [ + "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fd_test", + "name": "h2_fakesec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -7739,19 +7801,20 @@ }, { "args": [ - "large_metadata" + "hpack_size" ], "ci_platforms": [ + "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fd_test", + "name": "h2_fakesec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -7759,19 +7822,20 @@ }, { "args": [ - "load_reporting_hook" + "idempotent_request" ], "ci_platforms": [ + "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fd_test", + "name": "h2_fakesec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -7779,19 +7843,20 @@ }, { "args": [ - "max_concurrent_streams" + "invoke_large_request" ], "ci_platforms": [ + "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fd_test", + "name": "h2_fakesec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -7799,19 +7864,20 @@ }, { "args": [ - "max_message_length" + "large_metadata" ], "ci_platforms": [ + "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fd_test", + "name": "h2_fakesec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -7819,19 +7885,20 @@ }, { "args": [ - "negative_deadline" + "load_reporting_hook" ], "ci_platforms": [ + "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fd_test", + "name": "h2_fakesec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -7839,19 +7906,20 @@ }, { "args": [ - "network_status_change" + "max_concurrent_streams" ], "ci_platforms": [ + "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fd_test", + "name": "h2_fakesec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -7859,19 +7927,20 @@ }, { "args": [ - "no_logging" + "max_message_length" ], "ci_platforms": [ + "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fd_test", + "name": "h2_fakesec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -7879,19 +7948,20 @@ }, { "args": [ - "no_op" + "negative_deadline" ], "ci_platforms": [ + "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fd_test", + "name": "h2_fakesec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -7899,19 +7969,20 @@ }, { "args": [ - "payload" + "network_status_change" ], "ci_platforms": [ + "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fd_test", + "name": "h2_fakesec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -7919,19 +7990,20 @@ }, { "args": [ - "ping_pong_streaming" + "no_logging" ], "ci_platforms": [ + "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fd_test", + "name": "h2_fakesec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -7939,19 +8011,20 @@ }, { "args": [ - "registered_call" + "no_op" ], "ci_platforms": [ + "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fd_test", + "name": "h2_fakesec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -7959,19 +8032,20 @@ }, { "args": [ - "request_with_flags" + "payload" ], "ci_platforms": [ + "windows", "linux", - "mac", "posix" ], - "cpu_cost": 0.1, + "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fd_test", + "name": "h2_fakesec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -7979,19 +8053,20 @@ }, { "args": [ - "request_with_payload" + "ping" ], "ci_platforms": [ + "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fd_test", + "name": "h2_fakesec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -7999,19 +8074,20 @@ }, { "args": [ - "server_finishes_request" + "ping_pong_streaming" ], "ci_platforms": [ + "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fd_test", + "name": "h2_fakesec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -8019,19 +8095,20 @@ }, { "args": [ - "shutdown_finishes_calls" + "registered_call" ], "ci_platforms": [ + "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fd_test", + "name": "h2_fakesec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -8039,19 +8116,20 @@ }, { "args": [ - "shutdown_finishes_tags" + "request_with_flags" ], "ci_platforms": [ + "windows", "linux", - "mac", "posix" ], - "cpu_cost": 1.0, + "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fd_test", + "name": "h2_fakesec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -8059,19 +8137,20 @@ }, { "args": [ - "simple_cacheable_request" + "request_with_payload" ], "ci_platforms": [ + "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fd_test", + "name": "h2_fakesec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -8079,19 +8158,20 @@ }, { "args": [ - "simple_metadata" + "server_finishes_request" ], "ci_platforms": [ + "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fd_test", + "name": "h2_fakesec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -8099,19 +8179,20 @@ }, { "args": [ - "simple_request" + "shutdown_finishes_calls" ], "ci_platforms": [ + "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fd_test", + "name": "h2_fakesec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -8119,19 +8200,20 @@ }, { "args": [ - "streaming_error_response" + "shutdown_finishes_tags" ], "ci_platforms": [ + "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fd_test", + "name": "h2_fakesec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -8139,19 +8221,20 @@ }, { "args": [ - "trailing_metadata" + "simple_cacheable_request" ], "ci_platforms": [ + "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_fd_test", + "name": "h2_fakesec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -8159,19 +8242,18 @@ }, { "args": [ - "bad_hostname" + "simple_delayed_request" ], "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full_test", + "name": "h2_fakesec_test", "platforms": [ "windows", "linux", @@ -8181,19 +8263,18 @@ }, { "args": [ - "binary_metadata" + "simple_metadata" ], "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full_test", + "name": "h2_fakesec_test", "platforms": [ "windows", "linux", @@ -8203,19 +8284,18 @@ }, { "args": [ - "call_creds" + "simple_request" ], "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full_test", + "name": "h2_fakesec_test", "platforms": [ "windows", "linux", @@ -8225,19 +8305,18 @@ }, { "args": [ - "cancel_after_accept" + "streaming_error_response" ], "ci_platforms": [ "windows", "linux", - "mac", "posix" ], - "cpu_cost": 0.1, + "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full_test", + "name": "h2_fakesec_test", "platforms": [ "windows", "linux", @@ -8247,19 +8326,18 @@ }, { "args": [ - "cancel_after_client_done" + "trailing_metadata" ], "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full_test", + "name": "h2_fakesec_test", "platforms": [ "windows", "linux", @@ -8269,21 +8347,19 @@ }, { "args": [ - "cancel_after_invoke" + "bad_hostname" ], "ci_platforms": [ - "windows", "linux", "mac", "posix" ], - "cpu_cost": 0.1, + "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full_test", + "name": "h2_fd_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -8291,21 +8367,19 @@ }, { "args": [ - "cancel_before_invoke" + "binary_metadata" ], "ci_platforms": [ - "windows", "linux", "mac", "posix" ], - "cpu_cost": 0.1, + "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full_test", + "name": "h2_fd_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -8313,21 +8387,19 @@ }, { "args": [ - "cancel_in_a_vacuum" + "call_creds" ], "ci_platforms": [ - "windows", "linux", "mac", "posix" ], - "cpu_cost": 0.1, + "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full_test", + "name": "h2_fd_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -8335,10 +8407,9 @@ }, { "args": [ - "cancel_with_status" + "cancel_after_accept" ], "ci_platforms": [ - "windows", "linux", "mac", "posix" @@ -8347,9 +8418,8 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full_test", + "name": "h2_fd_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -8357,10 +8427,9 @@ }, { "args": [ - "compressed_payload" + "cancel_after_client_done" ], "ci_platforms": [ - "windows", "linux", "mac", "posix" @@ -8369,9 +8438,8 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full_test", + "name": "h2_fd_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -8379,10 +8447,9 @@ }, { "args": [ - "connectivity" + "cancel_after_invoke" ], "ci_platforms": [ - "windows", "linux", "mac", "posix" @@ -8391,9 +8458,8 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full_test", + "name": "h2_fd_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -8401,21 +8467,19 @@ }, { "args": [ - "default_host" + "cancel_before_invoke" ], "ci_platforms": [ - "windows", "linux", "mac", "posix" ], - "cpu_cost": 1.0, + "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full_test", + "name": "h2_fd_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -8423,21 +8487,19 @@ }, { "args": [ - "disappearing_server" + "cancel_in_a_vacuum" ], "ci_platforms": [ - "windows", "linux", "mac", "posix" ], - "cpu_cost": 1.0, + "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full_test", + "name": "h2_fd_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -8445,21 +8507,19 @@ }, { "args": [ - "empty_batch" + "cancel_with_status" ], "ci_platforms": [ - "windows", "linux", "mac", "posix" ], - "cpu_cost": 1.0, + "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full_test", + "name": "h2_fd_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -8467,10 +8527,9 @@ }, { "args": [ - "filter_call_init_fails" + "compressed_payload" ], "ci_platforms": [ - "windows", "linux", "mac", "posix" @@ -8479,9 +8538,8 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full_test", + "name": "h2_fd_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -8489,10 +8547,9 @@ }, { "args": [ - "filter_causes_close" + "empty_batch" ], "ci_platforms": [ - "windows", "linux", "mac", "posix" @@ -8501,9 +8558,8 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full_test", + "name": "h2_fd_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -8511,21 +8567,19 @@ }, { "args": [ - "graceful_server_shutdown" + "filter_call_init_fails" ], "ci_platforms": [ - "windows", "linux", "mac", "posix" ], - "cpu_cost": 0.1, + "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full_test", + "name": "h2_fd_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -8533,10 +8587,9 @@ }, { "args": [ - "high_initial_seqno" + "filter_causes_close" ], "ci_platforms": [ - "windows", "linux", "mac", "posix" @@ -8545,9 +8598,8 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full_test", + "name": "h2_fd_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -8555,21 +8607,19 @@ }, { "args": [ - "hpack_size" + "graceful_server_shutdown" ], "ci_platforms": [ - "windows", "linux", "mac", "posix" ], - "cpu_cost": 1.0, + "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full_test", + "name": "h2_fd_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -8577,10 +8627,9 @@ }, { "args": [ - "idempotent_request" + "high_initial_seqno" ], "ci_platforms": [ - "windows", "linux", "mac", "posix" @@ -8589,9 +8638,8 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full_test", + "name": "h2_fd_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -8599,10 +8647,9 @@ }, { "args": [ - "invoke_large_request" + "hpack_size" ], "ci_platforms": [ - "windows", "linux", "mac", "posix" @@ -8611,9 +8658,8 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full_test", + "name": "h2_fd_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -8621,10 +8667,9 @@ }, { "args": [ - "large_metadata" + "idempotent_request" ], "ci_platforms": [ - "windows", "linux", "mac", "posix" @@ -8633,9 +8678,8 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full_test", + "name": "h2_fd_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -8643,10 +8687,9 @@ }, { "args": [ - "load_reporting_hook" + "invoke_large_request" ], "ci_platforms": [ - "windows", "linux", "mac", "posix" @@ -8655,9 +8698,8 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full_test", + "name": "h2_fd_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -8665,10 +8707,9 @@ }, { "args": [ - "max_concurrent_streams" + "large_metadata" ], "ci_platforms": [ - "windows", "linux", "mac", "posix" @@ -8677,9 +8718,8 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full_test", + "name": "h2_fd_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -8687,10 +8727,9 @@ }, { "args": [ - "max_message_length" + "load_reporting_hook" ], "ci_platforms": [ - "windows", "linux", "mac", "posix" @@ -8699,9 +8738,8 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full_test", + "name": "h2_fd_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -8709,10 +8747,9 @@ }, { "args": [ - "negative_deadline" + "max_concurrent_streams" ], "ci_platforms": [ - "windows", "linux", "mac", "posix" @@ -8721,9 +8758,8 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full_test", + "name": "h2_fd_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -8731,10 +8767,9 @@ }, { "args": [ - "network_status_change" + "max_message_length" ], "ci_platforms": [ - "windows", "linux", "mac", "posix" @@ -8743,9 +8778,8 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full_test", + "name": "h2_fd_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -8753,10 +8787,9 @@ }, { "args": [ - "no_logging" + "negative_deadline" ], "ci_platforms": [ - "windows", "linux", "mac", "posix" @@ -8765,9 +8798,8 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full_test", + "name": "h2_fd_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -8775,10 +8807,9 @@ }, { "args": [ - "no_op" + "network_status_change" ], "ci_platforms": [ - "windows", "linux", "mac", "posix" @@ -8787,9 +8818,8 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full_test", + "name": "h2_fd_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -8797,10 +8827,9 @@ }, { "args": [ - "payload" + "no_logging" ], "ci_platforms": [ - "windows", "linux", "mac", "posix" @@ -8809,9 +8838,8 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full_test", + "name": "h2_fd_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -8819,10 +8847,9 @@ }, { "args": [ - "ping" + "no_op" ], "ci_platforms": [ - "windows", "linux", "mac", "posix" @@ -8831,9 +8858,8 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full_test", + "name": "h2_fd_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -8841,10 +8867,9 @@ }, { "args": [ - "ping_pong_streaming" + "payload" ], "ci_platforms": [ - "windows", "linux", "mac", "posix" @@ -8853,9 +8878,8 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full_test", + "name": "h2_fd_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -8863,10 +8887,9 @@ }, { "args": [ - "registered_call" + "ping_pong_streaming" ], "ci_platforms": [ - "windows", "linux", "mac", "posix" @@ -8875,9 +8898,8 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full_test", + "name": "h2_fd_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -8885,21 +8907,19 @@ }, { "args": [ - "request_with_flags" + "registered_call" ], "ci_platforms": [ - "windows", "linux", "mac", "posix" ], - "cpu_cost": 0.1, + "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full_test", + "name": "h2_fd_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -8907,21 +8927,19 @@ }, { "args": [ - "request_with_payload" + "request_with_flags" ], "ci_platforms": [ - "windows", "linux", "mac", "posix" ], - "cpu_cost": 1.0, + "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full_test", + "name": "h2_fd_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -8929,10 +8947,9 @@ }, { "args": [ - "server_finishes_request" + "request_with_payload" ], "ci_platforms": [ - "windows", "linux", "mac", "posix" @@ -8941,9 +8958,8 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full_test", + "name": "h2_fd_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -8951,10 +8967,9 @@ }, { "args": [ - "shutdown_finishes_calls" + "server_finishes_request" ], "ci_platforms": [ - "windows", "linux", "mac", "posix" @@ -8963,9 +8978,8 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full_test", + "name": "h2_fd_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -8973,10 +8987,9 @@ }, { "args": [ - "shutdown_finishes_tags" + "shutdown_finishes_calls" ], "ci_platforms": [ - "windows", "linux", "mac", "posix" @@ -8985,9 +8998,8 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full_test", + "name": "h2_fd_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -8995,10 +9007,9 @@ }, { "args": [ - "simple_cacheable_request" + "shutdown_finishes_tags" ], "ci_platforms": [ - "windows", "linux", "mac", "posix" @@ -9007,9 +9018,8 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full_test", + "name": "h2_fd_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -9017,10 +9027,9 @@ }, { "args": [ - "simple_delayed_request" + "simple_cacheable_request" ], "ci_platforms": [ - "windows", "linux", "mac", "posix" @@ -9029,9 +9038,8 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full_test", + "name": "h2_fd_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -9042,7 +9050,6 @@ "simple_metadata" ], "ci_platforms": [ - "windows", "linux", "mac", "posix" @@ -9051,9 +9058,8 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full_test", + "name": "h2_fd_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -9064,7 +9070,6 @@ "simple_request" ], "ci_platforms": [ - "windows", "linux", "mac", "posix" @@ -9073,9 +9078,8 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full_test", + "name": "h2_fd_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -9086,7 +9090,6 @@ "streaming_error_response" ], "ci_platforms": [ - "windows", "linux", "mac", "posix" @@ -9095,9 +9098,8 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full_test", + "name": "h2_fd_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -9108,7 +9110,6 @@ "trailing_metadata" ], "ci_platforms": [ - "windows", "linux", "mac", "posix" @@ -9117,9 +9118,8 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full_test", + "name": "h2_fd_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -9130,15 +9130,21 @@ "bad_hostname" ], "ci_platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+pipe_test", + "name": "h2_full_test", "platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ] }, { @@ -9146,15 +9152,21 @@ "binary_metadata" ], "ci_platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+pipe_test", + "name": "h2_full_test", "platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ] }, { @@ -9162,15 +9174,21 @@ "call_creds" ], "ci_platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+pipe_test", + "name": "h2_full_test", "platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ] }, { @@ -9178,15 +9196,21 @@ "cancel_after_accept" ], "ci_platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+pipe_test", + "name": "h2_full_test", "platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ] }, { @@ -9194,15 +9218,21 @@ "cancel_after_client_done" ], "ci_platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+pipe_test", + "name": "h2_full_test", "platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ] }, { @@ -9210,15 +9240,21 @@ "cancel_after_invoke" ], "ci_platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+pipe_test", + "name": "h2_full_test", "platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ] }, { @@ -9226,15 +9262,21 @@ "cancel_before_invoke" ], "ci_platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+pipe_test", + "name": "h2_full_test", "platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ] }, { @@ -9242,15 +9284,21 @@ "cancel_in_a_vacuum" ], "ci_platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+pipe_test", + "name": "h2_full_test", "platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ] }, { @@ -9258,15 +9306,21 @@ "cancel_with_status" ], "ci_platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+pipe_test", + "name": "h2_full_test", "platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ] }, { @@ -9274,15 +9328,21 @@ "compressed_payload" ], "ci_platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+pipe_test", + "name": "h2_full_test", "platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ] }, { @@ -9290,15 +9350,21 @@ "connectivity" ], "ci_platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+pipe_test", + "name": "h2_full_test", "platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ] }, { @@ -9306,15 +9372,21 @@ "default_host" ], "ci_platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+pipe_test", + "name": "h2_full_test", "platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ] }, { @@ -9322,15 +9394,21 @@ "disappearing_server" ], "ci_platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+pipe_test", + "name": "h2_full_test", "platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ] }, { @@ -9338,15 +9416,21 @@ "empty_batch" ], "ci_platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+pipe_test", + "name": "h2_full_test", "platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ] }, { @@ -9354,15 +9438,21 @@ "filter_call_init_fails" ], "ci_platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+pipe_test", + "name": "h2_full_test", "platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ] }, { @@ -9370,15 +9460,21 @@ "filter_causes_close" ], "ci_platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+pipe_test", + "name": "h2_full_test", "platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ] }, { @@ -9386,15 +9482,21 @@ "graceful_server_shutdown" ], "ci_platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+pipe_test", + "name": "h2_full_test", "platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ] }, { @@ -9402,15 +9504,21 @@ "high_initial_seqno" ], "ci_platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+pipe_test", + "name": "h2_full_test", "platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ] }, { @@ -9418,15 +9526,21 @@ "hpack_size" ], "ci_platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+pipe_test", + "name": "h2_full_test", "platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ] }, { @@ -9434,15 +9548,21 @@ "idempotent_request" ], "ci_platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+pipe_test", + "name": "h2_full_test", "platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ] }, { @@ -9450,15 +9570,21 @@ "invoke_large_request" ], "ci_platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+pipe_test", + "name": "h2_full_test", "platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ] }, { @@ -9466,15 +9592,21 @@ "large_metadata" ], "ci_platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+pipe_test", + "name": "h2_full_test", "platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ] }, { @@ -9482,15 +9614,21 @@ "load_reporting_hook" ], "ci_platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+pipe_test", + "name": "h2_full_test", "platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ] }, { @@ -9498,15 +9636,21 @@ "max_concurrent_streams" ], "ci_platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+pipe_test", + "name": "h2_full_test", "platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ] }, { @@ -9514,15 +9658,21 @@ "max_message_length" ], "ci_platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+pipe_test", + "name": "h2_full_test", "platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ] }, { @@ -9530,15 +9680,21 @@ "negative_deadline" ], "ci_platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+pipe_test", + "name": "h2_full_test", "platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ] }, { @@ -9546,15 +9702,21 @@ "network_status_change" ], "ci_platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+pipe_test", + "name": "h2_full_test", "platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ] }, { @@ -9562,15 +9724,21 @@ "no_logging" ], "ci_platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+pipe_test", + "name": "h2_full_test", "platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ] }, { @@ -9578,15 +9746,21 @@ "no_op" ], "ci_platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+pipe_test", + "name": "h2_full_test", "platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ] }, { @@ -9594,15 +9768,21 @@ "payload" ], "ci_platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+pipe_test", + "name": "h2_full_test", "platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ] }, { @@ -9610,15 +9790,21 @@ "ping" ], "ci_platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+pipe_test", + "name": "h2_full_test", "platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ] }, { @@ -9626,15 +9812,1649 @@ "ping_pong_streaming" ], "ci_platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+pipe_test", + "name": "h2_full_test", "platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "registered_call" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "request_with_flags" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 0.1, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "request_with_payload" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "server_finishes_request" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "shutdown_finishes_calls" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "shutdown_finishes_tags" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "simple_cacheable_request" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "simple_delayed_request" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "simple_metadata" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "simple_request" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "streaming_error_response" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "trailing_metadata" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "bad_hostname" + ], + "ci_platforms": [ + "linux" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+pipe_test", + "platforms": [ + "linux" + ] + }, + { + "args": [ + "binary_metadata" + ], + "ci_platforms": [ + "linux" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+pipe_test", + "platforms": [ + "linux" + ] + }, + { + "args": [ + "call_creds" + ], + "ci_platforms": [ + "linux" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+pipe_test", + "platforms": [ + "linux" + ] + }, + { + "args": [ + "cancel_after_accept" + ], + "ci_platforms": [ + "linux" + ], + "cpu_cost": 0.1, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+pipe_test", + "platforms": [ + "linux" + ] + }, + { + "args": [ + "cancel_after_client_done" + ], + "ci_platforms": [ + "linux" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+pipe_test", + "platforms": [ + "linux" + ] + }, + { + "args": [ + "cancel_after_invoke" + ], + "ci_platforms": [ + "linux" + ], + "cpu_cost": 0.1, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+pipe_test", + "platforms": [ + "linux" + ] + }, + { + "args": [ + "cancel_before_invoke" + ], + "ci_platforms": [ + "linux" + ], + "cpu_cost": 0.1, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+pipe_test", + "platforms": [ + "linux" + ] + }, + { + "args": [ + "cancel_in_a_vacuum" + ], + "ci_platforms": [ + "linux" + ], + "cpu_cost": 0.1, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+pipe_test", + "platforms": [ + "linux" + ] + }, + { + "args": [ + "cancel_with_status" + ], + "ci_platforms": [ + "linux" + ], + "cpu_cost": 0.1, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+pipe_test", + "platforms": [ + "linux" + ] + }, + { + "args": [ + "compressed_payload" + ], + "ci_platforms": [ + "linux" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+pipe_test", + "platforms": [ + "linux" + ] + }, + { + "args": [ + "connectivity" + ], + "ci_platforms": [ + "linux" + ], + "cpu_cost": 0.1, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+pipe_test", + "platforms": [ + "linux" + ] + }, + { + "args": [ + "default_host" + ], + "ci_platforms": [ + "linux" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+pipe_test", + "platforms": [ + "linux" + ] + }, + { + "args": [ + "disappearing_server" + ], + "ci_platforms": [ + "linux" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+pipe_test", + "platforms": [ + "linux" + ] + }, + { + "args": [ + "empty_batch" + ], + "ci_platforms": [ + "linux" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+pipe_test", + "platforms": [ + "linux" + ] + }, + { + "args": [ + "filter_call_init_fails" + ], + "ci_platforms": [ + "linux" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+pipe_test", + "platforms": [ + "linux" + ] + }, + { + "args": [ + "filter_causes_close" + ], + "ci_platforms": [ + "linux" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+pipe_test", + "platforms": [ + "linux" + ] + }, + { + "args": [ + "graceful_server_shutdown" + ], + "ci_platforms": [ + "linux" + ], + "cpu_cost": 0.1, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+pipe_test", + "platforms": [ + "linux" + ] + }, + { + "args": [ + "high_initial_seqno" + ], + "ci_platforms": [ + "linux" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+pipe_test", + "platforms": [ + "linux" + ] + }, + { + "args": [ + "hpack_size" + ], + "ci_platforms": [ + "linux" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+pipe_test", + "platforms": [ + "linux" + ] + }, + { + "args": [ + "idempotent_request" + ], + "ci_platforms": [ + "linux" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+pipe_test", + "platforms": [ + "linux" + ] + }, + { + "args": [ + "invoke_large_request" + ], + "ci_platforms": [ + "linux" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+pipe_test", + "platforms": [ + "linux" + ] + }, + { + "args": [ + "large_metadata" + ], + "ci_platforms": [ + "linux" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+pipe_test", + "platforms": [ + "linux" + ] + }, + { + "args": [ + "load_reporting_hook" + ], + "ci_platforms": [ + "linux" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+pipe_test", + "platforms": [ + "linux" + ] + }, + { + "args": [ + "max_concurrent_streams" + ], + "ci_platforms": [ + "linux" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+pipe_test", + "platforms": [ + "linux" + ] + }, + { + "args": [ + "max_message_length" + ], + "ci_platforms": [ + "linux" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+pipe_test", + "platforms": [ + "linux" + ] + }, + { + "args": [ + "negative_deadline" + ], + "ci_platforms": [ + "linux" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+pipe_test", + "platforms": [ + "linux" + ] + }, + { + "args": [ + "network_status_change" + ], + "ci_platforms": [ + "linux" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+pipe_test", + "platforms": [ + "linux" + ] + }, + { + "args": [ + "no_logging" + ], + "ci_platforms": [ + "linux" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+pipe_test", + "platforms": [ + "linux" + ] + }, + { + "args": [ + "no_op" + ], + "ci_platforms": [ + "linux" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+pipe_test", + "platforms": [ + "linux" + ] + }, + { + "args": [ + "payload" + ], + "ci_platforms": [ + "linux" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+pipe_test", + "platforms": [ + "linux" + ] + }, + { + "args": [ + "ping" + ], + "ci_platforms": [ + "linux" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+pipe_test", + "platforms": [ + "linux" + ] + }, + { + "args": [ + "ping_pong_streaming" + ], + "ci_platforms": [ + "linux" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+pipe_test", + "platforms": [ + "linux" + ] + }, + { + "args": [ + "registered_call" + ], + "ci_platforms": [ + "linux" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+pipe_test", + "platforms": [ + "linux" + ] + }, + { + "args": [ + "request_with_flags" + ], + "ci_platforms": [ + "linux" + ], + "cpu_cost": 0.1, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+pipe_test", + "platforms": [ + "linux" + ] + }, + { + "args": [ + "request_with_payload" + ], + "ci_platforms": [ + "linux" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+pipe_test", + "platforms": [ + "linux" + ] + }, + { + "args": [ + "server_finishes_request" + ], + "ci_platforms": [ + "linux" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+pipe_test", + "platforms": [ + "linux" + ] + }, + { + "args": [ + "shutdown_finishes_calls" + ], + "ci_platforms": [ + "linux" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+pipe_test", + "platforms": [ + "linux" + ] + }, + { + "args": [ + "shutdown_finishes_tags" + ], + "ci_platforms": [ + "linux" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+pipe_test", + "platforms": [ + "linux" + ] + }, + { + "args": [ + "simple_cacheable_request" + ], + "ci_platforms": [ + "linux" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+pipe_test", + "platforms": [ + "linux" + ] + }, + { + "args": [ + "simple_delayed_request" + ], + "ci_platforms": [ + "linux" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+pipe_test", + "platforms": [ + "linux" + ] + }, + { + "args": [ + "simple_metadata" + ], + "ci_platforms": [ + "linux" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+pipe_test", + "platforms": [ + "linux" + ] + }, + { + "args": [ + "simple_request" + ], + "ci_platforms": [ + "linux" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+pipe_test", + "platforms": [ + "linux" + ] + }, + { + "args": [ + "streaming_error_response" + ], + "ci_platforms": [ + "linux" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+pipe_test", + "platforms": [ + "linux" + ] + }, + { + "args": [ + "trailing_metadata" + ], + "ci_platforms": [ + "linux" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+pipe_test", + "platforms": [ + "linux" + ] + }, + { + "args": [ + "bad_hostname" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+trace_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "binary_metadata" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+trace_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "call_creds" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+trace_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "cancel_after_accept" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 0.1, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+trace_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "cancel_after_client_done" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+trace_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "cancel_after_invoke" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 0.1, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+trace_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "cancel_before_invoke" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 0.1, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+trace_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "cancel_in_a_vacuum" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 0.1, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+trace_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "cancel_with_status" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 0.1, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+trace_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "compressed_payload" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+trace_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "connectivity" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 0.1, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+trace_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "default_host" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+trace_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "disappearing_server" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+trace_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "empty_batch" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+trace_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "filter_call_init_fails" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+trace_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "filter_causes_close" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+trace_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "graceful_server_shutdown" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 0.1, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+trace_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "high_initial_seqno" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+trace_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "idempotent_request" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+trace_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "invoke_large_request" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+trace_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "large_metadata" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+trace_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "load_reporting_hook" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+trace_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "max_concurrent_streams" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+trace_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "max_message_length" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+trace_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "negative_deadline" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+trace_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "network_status_change" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+trace_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "no_op" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+trace_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "payload" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+trace_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "ping" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+trace_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "ping_pong_streaming" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_full+trace_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" ] }, { @@ -9642,15 +11462,21 @@ "registered_call" ], "ci_platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+pipe_test", + "name": "h2_full+trace_test", "platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ] }, { @@ -9658,15 +11484,21 @@ "request_with_flags" ], "ci_platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+pipe_test", + "name": "h2_full+trace_test", "platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ] }, { @@ -9674,15 +11506,21 @@ "request_with_payload" ], "ci_platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+pipe_test", + "name": "h2_full+trace_test", "platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ] }, { @@ -9690,15 +11528,21 @@ "server_finishes_request" ], "ci_platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+pipe_test", + "name": "h2_full+trace_test", "platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ] }, { @@ -9706,15 +11550,21 @@ "shutdown_finishes_calls" ], "ci_platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+pipe_test", + "name": "h2_full+trace_test", "platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ] }, { @@ -9722,15 +11572,21 @@ "shutdown_finishes_tags" ], "ci_platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+pipe_test", + "name": "h2_full+trace_test", "platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ] }, { @@ -9738,15 +11594,21 @@ "simple_cacheable_request" ], "ci_platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+pipe_test", + "name": "h2_full+trace_test", "platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ] }, { @@ -9754,15 +11616,21 @@ "simple_delayed_request" ], "ci_platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+pipe_test", + "name": "h2_full+trace_test", "platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ] }, { @@ -9770,15 +11638,21 @@ "simple_metadata" ], "ci_platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+pipe_test", + "name": "h2_full+trace_test", "platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ] }, { @@ -9786,15 +11660,21 @@ "simple_request" ], "ci_platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+pipe_test", + "name": "h2_full+trace_test", "platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ] }, { @@ -9802,15 +11682,21 @@ "streaming_error_response" ], "ci_platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+pipe_test", + "name": "h2_full+trace_test", "platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ] }, { @@ -9818,15 +11704,21 @@ "trailing_metadata" ], "ci_platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+pipe_test", + "name": "h2_full+trace_test", "platforms": [ - "linux" + "windows", + "linux", + "mac", + "posix" ] }, { @@ -9836,14 +11728,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+trace_test", + "name": "h2_http_proxy_test", "platforms": [ "windows", "linux", @@ -9858,14 +11749,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+trace_test", + "name": "h2_http_proxy_test", "platforms": [ "windows", "linux", @@ -9880,14 +11770,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+trace_test", + "name": "h2_http_proxy_test", "platforms": [ "windows", "linux", @@ -9902,14 +11791,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+trace_test", + "name": "h2_http_proxy_test", "platforms": [ "windows", "linux", @@ -9924,14 +11812,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+trace_test", + "name": "h2_http_proxy_test", "platforms": [ "windows", "linux", @@ -9946,14 +11833,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+trace_test", + "name": "h2_http_proxy_test", "platforms": [ "windows", "linux", @@ -9968,14 +11854,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+trace_test", + "name": "h2_http_proxy_test", "platforms": [ "windows", "linux", @@ -9990,14 +11875,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+trace_test", + "name": "h2_http_proxy_test", "platforms": [ "windows", "linux", @@ -10012,14 +11896,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+trace_test", + "name": "h2_http_proxy_test", "platforms": [ "windows", "linux", @@ -10034,14 +11917,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+trace_test", + "name": "h2_http_proxy_test", "platforms": [ "windows", "linux", @@ -10056,14 +11938,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+trace_test", + "name": "h2_http_proxy_test", "platforms": [ "windows", "linux", @@ -10078,14 +11959,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+trace_test", + "name": "h2_http_proxy_test", "platforms": [ "windows", "linux", @@ -10100,14 +11980,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+trace_test", + "name": "h2_http_proxy_test", "platforms": [ "windows", "linux", @@ -10122,14 +12001,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+trace_test", + "name": "h2_http_proxy_test", "platforms": [ "windows", "linux", @@ -10144,14 +12022,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+trace_test", + "name": "h2_http_proxy_test", "platforms": [ "windows", "linux", @@ -10166,14 +12043,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+trace_test", + "name": "h2_http_proxy_test", "platforms": [ "windows", "linux", @@ -10188,14 +12064,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+trace_test", + "name": "h2_http_proxy_test", "platforms": [ "windows", "linux", @@ -10208,16 +12083,36 @@ "high_initial_seqno" ], "ci_platforms": [ + "windows", + "linux", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_http_proxy_test", + "platforms": [ "windows", "linux", "mac", "posix" + ] + }, + { + "args": [ + "hpack_size" + ], + "ci_platforms": [ + "windows", + "linux", + "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+trace_test", + "name": "h2_http_proxy_test", "platforms": [ "windows", "linux", @@ -10232,14 +12127,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+trace_test", + "name": "h2_http_proxy_test", "platforms": [ "windows", "linux", @@ -10254,14 +12148,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+trace_test", + "name": "h2_http_proxy_test", "platforms": [ "windows", "linux", @@ -10276,14 +12169,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+trace_test", + "name": "h2_http_proxy_test", "platforms": [ "windows", "linux", @@ -10298,14 +12190,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+trace_test", + "name": "h2_http_proxy_test", "platforms": [ "windows", "linux", @@ -10320,14 +12211,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+trace_test", + "name": "h2_http_proxy_test", "platforms": [ "windows", "linux", @@ -10340,16 +12230,36 @@ "max_message_length" ], "ci_platforms": [ + "windows", + "linux", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_http_proxy_test", + "platforms": [ "windows", "linux", "mac", "posix" + ] + }, + { + "args": [ + "negative_deadline" + ], + "ci_platforms": [ + "windows", + "linux", + "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+trace_test", + "name": "h2_http_proxy_test", "platforms": [ "windows", "linux", @@ -10359,19 +12269,18 @@ }, { "args": [ - "negative_deadline" + "network_status_change" ], "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+trace_test", + "name": "h2_http_proxy_test", "platforms": [ "windows", "linux", @@ -10381,19 +12290,18 @@ }, { "args": [ - "network_status_change" + "no_logging" ], "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+trace_test", + "name": "h2_http_proxy_test", "platforms": [ "windows", "linux", @@ -10408,14 +12316,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+trace_test", + "name": "h2_http_proxy_test", "platforms": [ "windows", "linux", @@ -10430,14 +12337,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+trace_test", + "name": "h2_http_proxy_test", "platforms": [ "windows", "linux", @@ -10452,14 +12358,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+trace_test", + "name": "h2_http_proxy_test", "platforms": [ "windows", "linux", @@ -10474,14 +12379,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+trace_test", + "name": "h2_http_proxy_test", "platforms": [ "windows", "linux", @@ -10496,14 +12400,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+trace_test", + "name": "h2_http_proxy_test", "platforms": [ "windows", "linux", @@ -10518,14 +12421,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+trace_test", + "name": "h2_http_proxy_test", "platforms": [ "windows", "linux", @@ -10540,14 +12442,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+trace_test", + "name": "h2_http_proxy_test", "platforms": [ "windows", "linux", @@ -10562,14 +12463,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+trace_test", + "name": "h2_http_proxy_test", "platforms": [ "windows", "linux", @@ -10584,14 +12484,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+trace_test", + "name": "h2_http_proxy_test", "platforms": [ "windows", "linux", @@ -10606,14 +12505,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+trace_test", + "name": "h2_http_proxy_test", "platforms": [ "windows", "linux", @@ -10628,14 +12526,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+trace_test", + "name": "h2_http_proxy_test", "platforms": [ "windows", "linux", @@ -10650,14 +12547,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+trace_test", + "name": "h2_http_proxy_test", "platforms": [ "windows", "linux", @@ -10672,14 +12568,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+trace_test", + "name": "h2_http_proxy_test", "platforms": [ "windows", "linux", @@ -10694,14 +12589,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+trace_test", + "name": "h2_http_proxy_test", "platforms": [ "windows", "linux", @@ -10716,14 +12610,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+trace_test", + "name": "h2_http_proxy_test", "platforms": [ "windows", "linux", @@ -10738,14 +12631,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_full+trace_test", + "name": "h2_http_proxy_test", "platforms": [ "windows", "linux", @@ -10760,13 +12652,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_http_proxy_test", + "name": "h2_load_reporting_test", "platforms": [ "windows", "linux", @@ -10781,13 +12674,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_http_proxy_test", + "name": "h2_load_reporting_test", "platforms": [ "windows", "linux", @@ -10802,13 +12696,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_http_proxy_test", + "name": "h2_load_reporting_test", "platforms": [ "windows", "linux", @@ -10823,13 +12718,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_http_proxy_test", + "name": "h2_load_reporting_test", "platforms": [ "windows", "linux", @@ -10844,13 +12740,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_http_proxy_test", + "name": "h2_load_reporting_test", "platforms": [ "windows", "linux", @@ -10865,13 +12762,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_http_proxy_test", + "name": "h2_load_reporting_test", "platforms": [ "windows", "linux", @@ -10886,13 +12784,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_http_proxy_test", + "name": "h2_load_reporting_test", "platforms": [ "windows", "linux", @@ -10907,13 +12806,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_http_proxy_test", + "name": "h2_load_reporting_test", "platforms": [ "windows", "linux", @@ -10928,13 +12828,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_http_proxy_test", + "name": "h2_load_reporting_test", "platforms": [ "windows", "linux", @@ -10949,13 +12850,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_http_proxy_test", + "name": "h2_load_reporting_test", "platforms": [ "windows", "linux", @@ -10970,13 +12872,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_http_proxy_test", + "name": "h2_load_reporting_test", "platforms": [ "windows", "linux", @@ -10991,13 +12894,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_http_proxy_test", + "name": "h2_load_reporting_test", "platforms": [ "windows", "linux", @@ -11012,13 +12916,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_http_proxy_test", + "name": "h2_load_reporting_test", "platforms": [ "windows", "linux", @@ -11033,13 +12938,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_http_proxy_test", + "name": "h2_load_reporting_test", "platforms": [ "windows", "linux", @@ -11054,13 +12960,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_http_proxy_test", + "name": "h2_load_reporting_test", "platforms": [ "windows", "linux", @@ -11075,13 +12982,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_http_proxy_test", + "name": "h2_load_reporting_test", "platforms": [ "windows", "linux", @@ -11096,13 +13004,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_http_proxy_test", + "name": "h2_load_reporting_test", "platforms": [ "windows", "linux", @@ -11117,13 +13026,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_http_proxy_test", + "name": "h2_load_reporting_test", "platforms": [ "windows", "linux", @@ -11138,13 +13048,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_http_proxy_test", + "name": "h2_load_reporting_test", "platforms": [ "windows", "linux", @@ -11159,13 +13070,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_http_proxy_test", + "name": "h2_load_reporting_test", "platforms": [ "windows", "linux", @@ -11180,13 +13092,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_http_proxy_test", + "name": "h2_load_reporting_test", "platforms": [ "windows", "linux", @@ -11201,13 +13114,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_http_proxy_test", + "name": "h2_load_reporting_test", "platforms": [ "windows", "linux", @@ -11222,13 +13136,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_http_proxy_test", + "name": "h2_load_reporting_test", "platforms": [ "windows", "linux", @@ -11243,13 +13158,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_http_proxy_test", + "name": "h2_load_reporting_test", "platforms": [ "windows", "linux", @@ -11264,13 +13180,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_http_proxy_test", + "name": "h2_load_reporting_test", "platforms": [ "windows", "linux", @@ -11285,13 +13202,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_http_proxy_test", + "name": "h2_load_reporting_test", "platforms": [ "windows", "linux", @@ -11306,13 +13224,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_http_proxy_test", + "name": "h2_load_reporting_test", "platforms": [ "windows", "linux", @@ -11327,13 +13246,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_http_proxy_test", + "name": "h2_load_reporting_test", "platforms": [ "windows", "linux", @@ -11348,13 +13268,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_http_proxy_test", + "name": "h2_load_reporting_test", "platforms": [ "windows", "linux", @@ -11369,13 +13290,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_http_proxy_test", + "name": "h2_load_reporting_test", "platforms": [ "windows", "linux", @@ -11390,13 +13312,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_http_proxy_test", + "name": "h2_load_reporting_test", "platforms": [ "windows", "linux", @@ -11411,13 +13334,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_http_proxy_test", + "name": "h2_load_reporting_test", "platforms": [ "windows", "linux", @@ -11432,13 +13356,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_http_proxy_test", + "name": "h2_load_reporting_test", "platforms": [ "windows", "linux", @@ -11453,13 +13378,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_http_proxy_test", + "name": "h2_load_reporting_test", "platforms": [ "windows", "linux", @@ -11474,13 +13400,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_http_proxy_test", + "name": "h2_load_reporting_test", "platforms": [ "windows", "linux", @@ -11495,13 +13422,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_http_proxy_test", + "name": "h2_load_reporting_test", "platforms": [ "windows", "linux", @@ -11516,13 +13444,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_http_proxy_test", + "name": "h2_load_reporting_test", "platforms": [ "windows", "linux", @@ -11537,13 +13466,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_http_proxy_test", + "name": "h2_load_reporting_test", "platforms": [ "windows", "linux", @@ -11558,13 +13488,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_http_proxy_test", + "name": "h2_load_reporting_test", "platforms": [ "windows", "linux", @@ -11579,13 +13510,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_http_proxy_test", + "name": "h2_load_reporting_test", "platforms": [ "windows", "linux", @@ -11600,13 +13532,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_http_proxy_test", + "name": "h2_load_reporting_test", "platforms": [ "windows", "linux", @@ -11621,13 +13554,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_http_proxy_test", + "name": "h2_load_reporting_test", "platforms": [ "windows", "linux", @@ -11642,13 +13576,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_http_proxy_test", + "name": "h2_load_reporting_test", "platforms": [ "windows", "linux", @@ -11663,13 +13598,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_http_proxy_test", + "name": "h2_load_reporting_test", "platforms": [ "windows", "linux", @@ -11684,14 +13620,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_load_reporting_test", + "name": "h2_oauth2_test", "platforms": [ "windows", "linux", @@ -11706,14 +13641,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_load_reporting_test", + "name": "h2_oauth2_test", "platforms": [ "windows", "linux", @@ -11728,14 +13662,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_load_reporting_test", + "name": "h2_oauth2_test", "platforms": [ "windows", "linux", @@ -11750,14 +13683,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_load_reporting_test", + "name": "h2_oauth2_test", "platforms": [ "windows", "linux", @@ -11772,14 +13704,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_load_reporting_test", + "name": "h2_oauth2_test", "platforms": [ "windows", "linux", @@ -11794,14 +13725,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_load_reporting_test", + "name": "h2_oauth2_test", "platforms": [ "windows", "linux", @@ -11816,14 +13746,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_load_reporting_test", + "name": "h2_oauth2_test", "platforms": [ "windows", "linux", @@ -11838,14 +13767,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_load_reporting_test", + "name": "h2_oauth2_test", "platforms": [ "windows", "linux", @@ -11860,14 +13788,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_load_reporting_test", + "name": "h2_oauth2_test", "platforms": [ "windows", "linux", @@ -11882,14 +13809,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_load_reporting_test", + "name": "h2_oauth2_test", "platforms": [ "windows", "linux", @@ -11904,14 +13830,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_load_reporting_test", + "name": "h2_oauth2_test", "platforms": [ "windows", "linux", @@ -11926,14 +13851,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_load_reporting_test", + "name": "h2_oauth2_test", "platforms": [ "windows", "linux", @@ -11948,14 +13872,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_load_reporting_test", + "name": "h2_oauth2_test", "platforms": [ "windows", "linux", @@ -11970,14 +13893,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_load_reporting_test", + "name": "h2_oauth2_test", "platforms": [ "windows", "linux", @@ -11992,14 +13914,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_load_reporting_test", + "name": "h2_oauth2_test", "platforms": [ "windows", "linux", @@ -12014,14 +13935,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_load_reporting_test", + "name": "h2_oauth2_test", "platforms": [ "windows", "linux", @@ -12036,14 +13956,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_load_reporting_test", + "name": "h2_oauth2_test", "platforms": [ "windows", "linux", @@ -12058,14 +13977,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_load_reporting_test", + "name": "h2_oauth2_test", "platforms": [ "windows", "linux", @@ -12080,14 +13998,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_load_reporting_test", + "name": "h2_oauth2_test", "platforms": [ "windows", "linux", @@ -12102,14 +14019,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_load_reporting_test", + "name": "h2_oauth2_test", "platforms": [ "windows", "linux", @@ -12124,14 +14040,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_load_reporting_test", + "name": "h2_oauth2_test", "platforms": [ "windows", "linux", @@ -12146,14 +14061,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_load_reporting_test", + "name": "h2_oauth2_test", "platforms": [ "windows", "linux", @@ -12168,14 +14082,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_load_reporting_test", + "name": "h2_oauth2_test", "platforms": [ "windows", "linux", @@ -12190,14 +14103,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_load_reporting_test", + "name": "h2_oauth2_test", "platforms": [ "windows", "linux", @@ -12212,14 +14124,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_load_reporting_test", + "name": "h2_oauth2_test", "platforms": [ "windows", "linux", @@ -12234,14 +14145,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_load_reporting_test", + "name": "h2_oauth2_test", "platforms": [ "windows", "linux", @@ -12256,14 +14166,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_load_reporting_test", + "name": "h2_oauth2_test", "platforms": [ "windows", "linux", @@ -12278,14 +14187,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_load_reporting_test", + "name": "h2_oauth2_test", "platforms": [ "windows", "linux", @@ -12300,14 +14208,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_load_reporting_test", + "name": "h2_oauth2_test", "platforms": [ "windows", "linux", @@ -12322,14 +14229,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_load_reporting_test", + "name": "h2_oauth2_test", "platforms": [ "windows", "linux", @@ -12344,14 +14250,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_load_reporting_test", + "name": "h2_oauth2_test", "platforms": [ "windows", "linux", @@ -12366,14 +14271,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_load_reporting_test", + "name": "h2_oauth2_test", "platforms": [ "windows", "linux", @@ -12388,14 +14292,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_load_reporting_test", + "name": "h2_oauth2_test", "platforms": [ "windows", "linux", @@ -12410,14 +14313,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_load_reporting_test", + "name": "h2_oauth2_test", "platforms": [ "windows", "linux", @@ -12432,14 +14334,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_load_reporting_test", + "name": "h2_oauth2_test", "platforms": [ "windows", "linux", @@ -12454,14 +14355,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_load_reporting_test", + "name": "h2_oauth2_test", "platforms": [ "windows", "linux", @@ -12476,14 +14376,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_load_reporting_test", + "name": "h2_oauth2_test", "platforms": [ "windows", "linux", @@ -12498,14 +14397,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_load_reporting_test", + "name": "h2_oauth2_test", "platforms": [ "windows", "linux", @@ -12520,14 +14418,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_load_reporting_test", + "name": "h2_oauth2_test", "platforms": [ "windows", "linux", @@ -12542,14 +14439,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_load_reporting_test", + "name": "h2_oauth2_test", "platforms": [ "windows", "linux", @@ -12564,14 +14460,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_load_reporting_test", + "name": "h2_oauth2_test", "platforms": [ "windows", "linux", @@ -12586,14 +14481,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_load_reporting_test", + "name": "h2_oauth2_test", "platforms": [ "windows", "linux", @@ -12608,14 +14502,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_load_reporting_test", + "name": "h2_oauth2_test", "platforms": [ "windows", "linux", @@ -12630,14 +14523,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_load_reporting_test", + "name": "h2_oauth2_test", "platforms": [ "windows", "linux", @@ -12658,7 +14550,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_oauth2_test", + "name": "h2_proxy_test", "platforms": [ "windows", "linux", @@ -12679,7 +14571,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_oauth2_test", + "name": "h2_proxy_test", "platforms": [ "windows", "linux", @@ -12700,7 +14592,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_oauth2_test", + "name": "h2_proxy_test", "platforms": [ "windows", "linux", @@ -12721,7 +14613,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_oauth2_test", + "name": "h2_proxy_test", "platforms": [ "windows", "linux", @@ -12742,7 +14634,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_oauth2_test", + "name": "h2_proxy_test", "platforms": [ "windows", "linux", @@ -12763,7 +14655,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_oauth2_test", + "name": "h2_proxy_test", "platforms": [ "windows", "linux", @@ -12784,7 +14676,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_oauth2_test", + "name": "h2_proxy_test", "platforms": [ "windows", "linux", @@ -12805,7 +14697,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_oauth2_test", + "name": "h2_proxy_test", "platforms": [ "windows", "linux", @@ -12826,49 +14718,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_oauth2_test", - "platforms": [ - "windows", - "linux", - "mac", - "posix" - ] - }, - { - "args": [ - "compressed_payload" - ], - "ci_platforms": [ - "windows", - "linux", - "posix" - ], - "cpu_cost": 1.0, - "exclude_configs": [], - "flaky": false, - "language": "c", - "name": "h2_oauth2_test", - "platforms": [ - "windows", - "linux", - "mac", - "posix" - ] - }, - { - "args": [ - "connectivity" - ], - "ci_platforms": [ - "windows", - "linux", - "posix" - ], - "cpu_cost": 0.1, - "exclude_configs": [], - "flaky": false, - "language": "c", - "name": "h2_oauth2_test", + "name": "h2_proxy_test", "platforms": [ "windows", "linux", @@ -12889,7 +14739,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_oauth2_test", + "name": "h2_proxy_test", "platforms": [ "windows", "linux", @@ -12910,7 +14760,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_oauth2_test", + "name": "h2_proxy_test", "platforms": [ "windows", "linux", @@ -12931,7 +14781,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_oauth2_test", + "name": "h2_proxy_test", "platforms": [ "windows", "linux", @@ -12952,7 +14802,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_oauth2_test", + "name": "h2_proxy_test", "platforms": [ "windows", "linux", @@ -12973,7 +14823,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_oauth2_test", + "name": "h2_proxy_test", "platforms": [ "windows", "linux", @@ -12994,7 +14844,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_oauth2_test", + "name": "h2_proxy_test", "platforms": [ "windows", "linux", @@ -13015,28 +14865,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_oauth2_test", - "platforms": [ - "windows", - "linux", - "mac", - "posix" - ] - }, - { - "args": [ - "hpack_size" - ], - "ci_platforms": [ - "windows", - "linux", - "posix" - ], - "cpu_cost": 1.0, - "exclude_configs": [], - "flaky": false, - "language": "c", - "name": "h2_oauth2_test", + "name": "h2_proxy_test", "platforms": [ "windows", "linux", @@ -13057,7 +14886,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_oauth2_test", + "name": "h2_proxy_test", "platforms": [ "windows", "linux", @@ -13078,7 +14907,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_oauth2_test", + "name": "h2_proxy_test", "platforms": [ "windows", "linux", @@ -13099,7 +14928,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_oauth2_test", + "name": "h2_proxy_test", "platforms": [ "windows", "linux", @@ -13120,28 +14949,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_oauth2_test", - "platforms": [ - "windows", - "linux", - "mac", - "posix" - ] - }, - { - "args": [ - "max_concurrent_streams" - ], - "ci_platforms": [ - "windows", - "linux", - "posix" - ], - "cpu_cost": 1.0, - "exclude_configs": [], - "flaky": false, - "language": "c", - "name": "h2_oauth2_test", + "name": "h2_proxy_test", "platforms": [ "windows", "linux", @@ -13162,7 +14970,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_oauth2_test", + "name": "h2_proxy_test", "platforms": [ "windows", "linux", @@ -13183,7 +14991,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_oauth2_test", + "name": "h2_proxy_test", "platforms": [ "windows", "linux", @@ -13204,7 +15012,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_oauth2_test", + "name": "h2_proxy_test", "platforms": [ "windows", "linux", @@ -13225,7 +15033,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_oauth2_test", + "name": "h2_proxy_test", "platforms": [ "windows", "linux", @@ -13246,7 +15054,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_oauth2_test", + "name": "h2_proxy_test", "platforms": [ "windows", "linux", @@ -13267,28 +15075,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_oauth2_test", - "platforms": [ - "windows", - "linux", - "mac", - "posix" - ] - }, - { - "args": [ - "ping" - ], - "ci_platforms": [ - "windows", - "linux", - "posix" - ], - "cpu_cost": 1.0, - "exclude_configs": [], - "flaky": false, - "language": "c", - "name": "h2_oauth2_test", + "name": "h2_proxy_test", "platforms": [ "windows", "linux", @@ -13309,7 +15096,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_oauth2_test", + "name": "h2_proxy_test", "platforms": [ "windows", "linux", @@ -13330,28 +15117,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_oauth2_test", - "platforms": [ - "windows", - "linux", - "mac", - "posix" - ] - }, - { - "args": [ - "request_with_flags" - ], - "ci_platforms": [ - "windows", - "linux", - "posix" - ], - "cpu_cost": 0.1, - "exclude_configs": [], - "flaky": false, - "language": "c", - "name": "h2_oauth2_test", + "name": "h2_proxy_test", "platforms": [ "windows", "linux", @@ -13372,7 +15138,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_oauth2_test", + "name": "h2_proxy_test", "platforms": [ "windows", "linux", @@ -13393,7 +15159,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_oauth2_test", + "name": "h2_proxy_test", "platforms": [ "windows", "linux", @@ -13414,7 +15180,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_oauth2_test", + "name": "h2_proxy_test", "platforms": [ "windows", "linux", @@ -13435,7 +15201,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_oauth2_test", + "name": "h2_proxy_test", "platforms": [ "windows", "linux", @@ -13456,7 +15222,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_oauth2_test", + "name": "h2_proxy_test", "platforms": [ "windows", "linux", @@ -13477,7 +15243,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_oauth2_test", + "name": "h2_proxy_test", "platforms": [ "windows", "linux", @@ -13498,7 +15264,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_oauth2_test", + "name": "h2_proxy_test", "platforms": [ "windows", "linux", @@ -13519,7 +15285,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_oauth2_test", + "name": "h2_proxy_test", "platforms": [ "windows", "linux", @@ -13540,7 +15306,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_oauth2_test", + "name": "h2_proxy_test", "platforms": [ "windows", "linux", @@ -13561,7 +15327,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_oauth2_test", + "name": "h2_proxy_test", "platforms": [ "windows", "linux", @@ -13582,7 +15348,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_proxy_test", + "name": "h2_sockpair_test", "platforms": [ "windows", "linux", @@ -13603,7 +15369,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_proxy_test", + "name": "h2_sockpair_test", "platforms": [ "windows", "linux", @@ -13624,7 +15390,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_proxy_test", + "name": "h2_sockpair_test", "platforms": [ "windows", "linux", @@ -13645,7 +15411,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_proxy_test", + "name": "h2_sockpair_test", "platforms": [ "windows", "linux", @@ -13666,7 +15432,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_proxy_test", + "name": "h2_sockpair_test", "platforms": [ "windows", "linux", @@ -13687,7 +15453,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_proxy_test", + "name": "h2_sockpair_test", "platforms": [ "windows", "linux", @@ -13708,7 +15474,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_proxy_test", + "name": "h2_sockpair_test", "platforms": [ "windows", "linux", @@ -13729,7 +15495,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_proxy_test", + "name": "h2_sockpair_test", "platforms": [ "windows", "linux", @@ -13750,7 +15516,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_proxy_test", + "name": "h2_sockpair_test", "platforms": [ "windows", "linux", @@ -13760,7 +15526,7 @@ }, { "args": [ - "default_host" + "compressed_payload" ], "ci_platforms": [ "windows", @@ -13771,7 +15537,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_proxy_test", + "name": "h2_sockpair_test", "platforms": [ "windows", "linux", @@ -13781,7 +15547,7 @@ }, { "args": [ - "disappearing_server" + "empty_batch" ], "ci_platforms": [ "windows", @@ -13792,7 +15558,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_proxy_test", + "name": "h2_sockpair_test", "platforms": [ "windows", "linux", @@ -13802,7 +15568,7 @@ }, { "args": [ - "empty_batch" + "filter_call_init_fails" ], "ci_platforms": [ "windows", @@ -13813,7 +15579,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_proxy_test", + "name": "h2_sockpair_test", "platforms": [ "windows", "linux", @@ -13823,7 +15589,7 @@ }, { "args": [ - "filter_call_init_fails" + "filter_causes_close" ], "ci_platforms": [ "windows", @@ -13834,7 +15600,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_proxy_test", + "name": "h2_sockpair_test", "platforms": [ "windows", "linux", @@ -13844,18 +15610,18 @@ }, { "args": [ - "filter_causes_close" + "graceful_server_shutdown" ], "ci_platforms": [ "windows", "linux", "posix" ], - "cpu_cost": 1.0, + "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_proxy_test", + "name": "h2_sockpair_test", "platforms": [ "windows", "linux", @@ -13865,18 +15631,18 @@ }, { "args": [ - "graceful_server_shutdown" + "high_initial_seqno" ], "ci_platforms": [ "windows", "linux", "posix" ], - "cpu_cost": 0.1, + "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_proxy_test", + "name": "h2_sockpair_test", "platforms": [ "windows", "linux", @@ -13886,7 +15652,7 @@ }, { "args": [ - "high_initial_seqno" + "hpack_size" ], "ci_platforms": [ "windows", @@ -13897,7 +15663,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_proxy_test", + "name": "h2_sockpair_test", "platforms": [ "windows", "linux", @@ -13918,7 +15684,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_proxy_test", + "name": "h2_sockpair_test", "platforms": [ "windows", "linux", @@ -13939,7 +15705,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_proxy_test", + "name": "h2_sockpair_test", "platforms": [ "windows", "linux", @@ -13960,7 +15726,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_proxy_test", + "name": "h2_sockpair_test", "platforms": [ "windows", "linux", @@ -13981,7 +15747,28 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_proxy_test", + "name": "h2_sockpair_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "max_concurrent_streams" + ], + "ci_platforms": [ + "windows", + "linux", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_sockpair_test", "platforms": [ "windows", "linux", @@ -14002,7 +15789,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_proxy_test", + "name": "h2_sockpair_test", "platforms": [ "windows", "linux", @@ -14023,7 +15810,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_proxy_test", + "name": "h2_sockpair_test", "platforms": [ "windows", "linux", @@ -14044,7 +15831,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_proxy_test", + "name": "h2_sockpair_test", "platforms": [ "windows", "linux", @@ -14065,7 +15852,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_proxy_test", + "name": "h2_sockpair_test", "platforms": [ "windows", "linux", @@ -14086,7 +15873,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_proxy_test", + "name": "h2_sockpair_test", "platforms": [ "windows", "linux", @@ -14107,7 +15894,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_proxy_test", + "name": "h2_sockpair_test", "platforms": [ "windows", "linux", @@ -14128,7 +15915,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_proxy_test", + "name": "h2_sockpair_test", "platforms": [ "windows", "linux", @@ -14149,7 +15936,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_proxy_test", + "name": "h2_sockpair_test", "platforms": [ "windows", "linux", @@ -14159,18 +15946,18 @@ }, { "args": [ - "request_with_payload" + "request_with_flags" ], "ci_platforms": [ "windows", "linux", "posix" ], - "cpu_cost": 1.0, + "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_proxy_test", + "name": "h2_sockpair_test", "platforms": [ "windows", "linux", @@ -14180,7 +15967,7 @@ }, { "args": [ - "server_finishes_request" + "request_with_payload" ], "ci_platforms": [ "windows", @@ -14191,7 +15978,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_proxy_test", + "name": "h2_sockpair_test", "platforms": [ "windows", "linux", @@ -14201,7 +15988,7 @@ }, { "args": [ - "shutdown_finishes_calls" + "server_finishes_request" ], "ci_platforms": [ "windows", @@ -14212,7 +15999,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_proxy_test", + "name": "h2_sockpair_test", "platforms": [ "windows", "linux", @@ -14222,7 +16009,7 @@ }, { "args": [ - "shutdown_finishes_tags" + "shutdown_finishes_calls" ], "ci_platforms": [ "windows", @@ -14233,7 +16020,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_proxy_test", + "name": "h2_sockpair_test", "platforms": [ "windows", "linux", @@ -14243,7 +16030,7 @@ }, { "args": [ - "simple_cacheable_request" + "shutdown_finishes_tags" ], "ci_platforms": [ "windows", @@ -14254,7 +16041,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_proxy_test", + "name": "h2_sockpair_test", "platforms": [ "windows", "linux", @@ -14264,7 +16051,7 @@ }, { "args": [ - "simple_delayed_request" + "simple_cacheable_request" ], "ci_platforms": [ "windows", @@ -14275,7 +16062,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_proxy_test", + "name": "h2_sockpair_test", "platforms": [ "windows", "linux", @@ -14296,7 +16083,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_proxy_test", + "name": "h2_sockpair_test", "platforms": [ "windows", "linux", @@ -14317,7 +16104,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_proxy_test", + "name": "h2_sockpair_test", "platforms": [ "windows", "linux", @@ -14338,7 +16125,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_proxy_test", + "name": "h2_sockpair_test", "platforms": [ "windows", "linux", @@ -14359,7 +16146,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_proxy_test", + "name": "h2_sockpair_test", "platforms": [ "windows", "linux", @@ -14380,7 +16167,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_test", + "name": "h2_sockpair+trace_test", "platforms": [ "windows", "linux", @@ -14401,7 +16188,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_test", + "name": "h2_sockpair+trace_test", "platforms": [ "windows", "linux", @@ -14422,7 +16209,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_test", + "name": "h2_sockpair+trace_test", "platforms": [ "windows", "linux", @@ -14443,7 +16230,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_test", + "name": "h2_sockpair+trace_test", "platforms": [ "windows", "linux", @@ -14464,7 +16251,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_test", + "name": "h2_sockpair+trace_test", "platforms": [ "windows", "linux", @@ -14485,7 +16272,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_test", + "name": "h2_sockpair+trace_test", "platforms": [ "windows", "linux", @@ -14506,7 +16293,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_test", + "name": "h2_sockpair+trace_test", "platforms": [ "windows", "linux", @@ -14527,7 +16314,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_test", + "name": "h2_sockpair+trace_test", "platforms": [ "windows", "linux", @@ -14548,7 +16335,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_test", + "name": "h2_sockpair+trace_test", "platforms": [ "windows", "linux", @@ -14569,7 +16356,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_test", + "name": "h2_sockpair+trace_test", "platforms": [ "windows", "linux", @@ -14590,7 +16377,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_test", + "name": "h2_sockpair+trace_test", "platforms": [ "windows", "linux", @@ -14611,7 +16398,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_test", + "name": "h2_sockpair+trace_test", "platforms": [ "windows", "linux", @@ -14632,7 +16419,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_test", + "name": "h2_sockpair+trace_test", "platforms": [ "windows", "linux", @@ -14653,7 +16440,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_test", + "name": "h2_sockpair+trace_test", "platforms": [ "windows", "linux", @@ -14674,28 +16461,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_test", - "platforms": [ - "windows", - "linux", - "mac", - "posix" - ] - }, - { - "args": [ - "hpack_size" - ], - "ci_platforms": [ - "windows", - "linux", - "posix" - ], - "cpu_cost": 1.0, - "exclude_configs": [], - "flaky": false, - "language": "c", - "name": "h2_sockpair_test", + "name": "h2_sockpair+trace_test", "platforms": [ "windows", "linux", @@ -14716,7 +16482,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_test", + "name": "h2_sockpair+trace_test", "platforms": [ "windows", "linux", @@ -14737,7 +16503,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_test", + "name": "h2_sockpair+trace_test", "platforms": [ "windows", "linux", @@ -14758,7 +16524,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_test", + "name": "h2_sockpair+trace_test", "platforms": [ "windows", "linux", @@ -14779,7 +16545,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_test", + "name": "h2_sockpair+trace_test", "platforms": [ "windows", "linux", @@ -14800,7 +16566,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_test", + "name": "h2_sockpair+trace_test", "platforms": [ "windows", "linux", @@ -14821,7 +16587,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_test", + "name": "h2_sockpair+trace_test", "platforms": [ "windows", "linux", @@ -14842,7 +16608,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_test", + "name": "h2_sockpair+trace_test", "platforms": [ "windows", "linux", @@ -14863,28 +16629,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_test", - "platforms": [ - "windows", - "linux", - "mac", - "posix" - ] - }, - { - "args": [ - "no_logging" - ], - "ci_platforms": [ - "windows", - "linux", - "posix" - ], - "cpu_cost": 1.0, - "exclude_configs": [], - "flaky": false, - "language": "c", - "name": "h2_sockpair_test", + "name": "h2_sockpair+trace_test", "platforms": [ "windows", "linux", @@ -14905,7 +16650,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_test", + "name": "h2_sockpair+trace_test", "platforms": [ "windows", "linux", @@ -14926,7 +16671,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_test", + "name": "h2_sockpair+trace_test", "platforms": [ "windows", "linux", @@ -14947,7 +16692,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_test", + "name": "h2_sockpair+trace_test", "platforms": [ "windows", "linux", @@ -14968,7 +16713,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_test", + "name": "h2_sockpair+trace_test", "platforms": [ "windows", "linux", @@ -14989,7 +16734,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_test", + "name": "h2_sockpair+trace_test", "platforms": [ "windows", "linux", @@ -15010,7 +16755,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_test", + "name": "h2_sockpair+trace_test", "platforms": [ "windows", "linux", @@ -15031,7 +16776,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_test", + "name": "h2_sockpair+trace_test", "platforms": [ "windows", "linux", @@ -15052,7 +16797,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_test", + "name": "h2_sockpair+trace_test", "platforms": [ "windows", "linux", @@ -15073,7 +16818,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_test", + "name": "h2_sockpair+trace_test", "platforms": [ "windows", "linux", @@ -15094,7 +16839,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_test", + "name": "h2_sockpair+trace_test", "platforms": [ "windows", "linux", @@ -15115,7 +16860,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_test", + "name": "h2_sockpair+trace_test", "platforms": [ "windows", "linux", @@ -15136,7 +16881,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_test", + "name": "h2_sockpair+trace_test", "platforms": [ "windows", "linux", @@ -15157,7 +16902,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_test", + "name": "h2_sockpair+trace_test", "platforms": [ "windows", "linux", @@ -15178,7 +16923,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_test", + "name": "h2_sockpair+trace_test", "platforms": [ "windows", "linux", @@ -15199,7 +16944,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair+trace_test", + "name": "h2_sockpair_1byte_test", "platforms": [ "windows", "linux", @@ -15220,7 +16965,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair+trace_test", + "name": "h2_sockpair_1byte_test", "platforms": [ "windows", "linux", @@ -15241,7 +16986,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair+trace_test", + "name": "h2_sockpair_1byte_test", "platforms": [ "windows", "linux", @@ -15262,7 +17007,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair+trace_test", + "name": "h2_sockpair_1byte_test", "platforms": [ "windows", "linux", @@ -15283,7 +17028,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair+trace_test", + "name": "h2_sockpair_1byte_test", "platforms": [ "windows", "linux", @@ -15304,7 +17049,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair+trace_test", + "name": "h2_sockpair_1byte_test", "platforms": [ "windows", "linux", @@ -15325,7 +17070,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair+trace_test", + "name": "h2_sockpair_1byte_test", "platforms": [ "windows", "linux", @@ -15346,7 +17091,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair+trace_test", + "name": "h2_sockpair_1byte_test", "platforms": [ "windows", "linux", @@ -15367,7 +17112,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair+trace_test", + "name": "h2_sockpair_1byte_test", "platforms": [ "windows", "linux", @@ -15388,7 +17133,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair+trace_test", + "name": "h2_sockpair_1byte_test", "platforms": [ "windows", "linux", @@ -15409,7 +17154,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair+trace_test", + "name": "h2_sockpair_1byte_test", "platforms": [ "windows", "linux", @@ -15430,7 +17175,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair+trace_test", + "name": "h2_sockpair_1byte_test", "platforms": [ "windows", "linux", @@ -15451,7 +17196,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair+trace_test", + "name": "h2_sockpair_1byte_test", "platforms": [ "windows", "linux", @@ -15472,7 +17217,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair+trace_test", + "name": "h2_sockpair_1byte_test", "platforms": [ "windows", "linux", @@ -15493,7 +17238,28 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair+trace_test", + "name": "h2_sockpair_1byte_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "hpack_size" + ], + "ci_platforms": [ + "windows", + "linux", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_sockpair_1byte_test", "platforms": [ "windows", "linux", @@ -15514,7 +17280,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair+trace_test", + "name": "h2_sockpair_1byte_test", "platforms": [ "windows", "linux", @@ -15535,7 +17301,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair+trace_test", + "name": "h2_sockpair_1byte_test", "platforms": [ "windows", "linux", @@ -15556,7 +17322,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair+trace_test", + "name": "h2_sockpair_1byte_test", "platforms": [ "windows", "linux", @@ -15577,7 +17343,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair+trace_test", + "name": "h2_sockpair_1byte_test", "platforms": [ "windows", "linux", @@ -15598,7 +17364,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair+trace_test", + "name": "h2_sockpair_1byte_test", "platforms": [ "windows", "linux", @@ -15619,7 +17385,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair+trace_test", + "name": "h2_sockpair_1byte_test", "platforms": [ "windows", "linux", @@ -15640,7 +17406,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair+trace_test", + "name": "h2_sockpair_1byte_test", "platforms": [ "windows", "linux", @@ -15661,7 +17427,28 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair+trace_test", + "name": "h2_sockpair_1byte_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "no_logging" + ], + "ci_platforms": [ + "windows", + "linux", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_sockpair_1byte_test", "platforms": [ "windows", "linux", @@ -15682,7 +17469,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair+trace_test", + "name": "h2_sockpair_1byte_test", "platforms": [ "windows", "linux", @@ -15703,7 +17490,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair+trace_test", + "name": "h2_sockpair_1byte_test", "platforms": [ "windows", "linux", @@ -15724,7 +17511,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair+trace_test", + "name": "h2_sockpair_1byte_test", "platforms": [ "windows", "linux", @@ -15745,7 +17532,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair+trace_test", + "name": "h2_sockpair_1byte_test", "platforms": [ "windows", "linux", @@ -15766,7 +17553,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair+trace_test", + "name": "h2_sockpair_1byte_test", "platforms": [ "windows", "linux", @@ -15787,7 +17574,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair+trace_test", + "name": "h2_sockpair_1byte_test", "platforms": [ "windows", "linux", @@ -15808,7 +17595,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair+trace_test", + "name": "h2_sockpair_1byte_test", "platforms": [ "windows", "linux", @@ -15829,7 +17616,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair+trace_test", + "name": "h2_sockpair_1byte_test", "platforms": [ "windows", "linux", @@ -15850,7 +17637,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair+trace_test", + "name": "h2_sockpair_1byte_test", "platforms": [ "windows", "linux", @@ -15871,7 +17658,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair+trace_test", + "name": "h2_sockpair_1byte_test", "platforms": [ "windows", "linux", @@ -15892,7 +17679,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair+trace_test", + "name": "h2_sockpair_1byte_test", "platforms": [ "windows", "linux", @@ -15913,7 +17700,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair+trace_test", + "name": "h2_sockpair_1byte_test", "platforms": [ "windows", "linux", @@ -15934,7 +17721,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair+trace_test", + "name": "h2_sockpair_1byte_test", "platforms": [ "windows", "linux", @@ -15955,7 +17742,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair+trace_test", + "name": "h2_sockpair_1byte_test", "platforms": [ "windows", "linux", @@ -15970,13 +17757,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_1byte_test", + "name": "h2_ssl_test", "platforms": [ "windows", "linux", @@ -15991,13 +17779,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_1byte_test", + "name": "h2_ssl_test", "platforms": [ "windows", "linux", @@ -16012,13 +17801,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_1byte_test", + "name": "h2_ssl_test", "platforms": [ "windows", "linux", @@ -16033,13 +17823,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_1byte_test", + "name": "h2_ssl_test", "platforms": [ "windows", "linux", @@ -16054,13 +17845,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_1byte_test", + "name": "h2_ssl_test", "platforms": [ "windows", "linux", @@ -16075,13 +17867,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_1byte_test", + "name": "h2_ssl_test", "platforms": [ "windows", "linux", @@ -16096,13 +17889,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_1byte_test", + "name": "h2_ssl_test", "platforms": [ "windows", "linux", @@ -16117,13 +17911,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_1byte_test", + "name": "h2_ssl_test", "platforms": [ "windows", "linux", @@ -16138,13 +17933,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_1byte_test", + "name": "h2_ssl_test", "platforms": [ "windows", "linux", @@ -16159,13 +17955,80 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_1byte_test", + "name": "h2_ssl_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "connectivity" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 0.1, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_ssl_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "default_host" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_ssl_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "disappearing_server" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_ssl_test", "platforms": [ "windows", "linux", @@ -16180,13 +18043,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_1byte_test", + "name": "h2_ssl_test", "platforms": [ "windows", "linux", @@ -16201,13 +18065,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_1byte_test", + "name": "h2_ssl_test", "platforms": [ "windows", "linux", @@ -16222,13 +18087,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_1byte_test", + "name": "h2_ssl_test", "platforms": [ "windows", "linux", @@ -16243,13 +18109,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_1byte_test", + "name": "h2_ssl_test", "platforms": [ "windows", "linux", @@ -16264,13 +18131,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_1byte_test", + "name": "h2_ssl_test", "platforms": [ "windows", "linux", @@ -16285,13 +18153,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_1byte_test", + "name": "h2_ssl_test", "platforms": [ "windows", "linux", @@ -16306,13 +18175,36 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_1byte_test", + "name": "h2_ssl_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "invoke_large_request" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_ssl_test", "platforms": [ "windows", "linux", @@ -16322,18 +18214,19 @@ }, { "args": [ - "invoke_large_request" + "large_metadata" ], "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_1byte_test", + "name": "h2_ssl_test", "platforms": [ "windows", "linux", @@ -16343,18 +18236,19 @@ }, { "args": [ - "large_metadata" + "load_reporting_hook" ], "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_1byte_test", + "name": "h2_ssl_test", "platforms": [ "windows", "linux", @@ -16364,18 +18258,19 @@ }, { "args": [ - "load_reporting_hook" + "max_concurrent_streams" ], "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_1byte_test", + "name": "h2_ssl_test", "platforms": [ "windows", "linux", @@ -16385,18 +18280,19 @@ }, { "args": [ - "max_concurrent_streams" + "max_message_length" ], "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_1byte_test", + "name": "h2_ssl_test", "platforms": [ "windows", "linux", @@ -16406,18 +18302,19 @@ }, { "args": [ - "max_message_length" + "negative_deadline" ], "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_1byte_test", + "name": "h2_ssl_test", "platforms": [ "windows", "linux", @@ -16427,18 +18324,19 @@ }, { "args": [ - "negative_deadline" + "network_status_change" ], "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_1byte_test", + "name": "h2_ssl_test", "platforms": [ "windows", "linux", @@ -16448,18 +18346,19 @@ }, { "args": [ - "network_status_change" + "no_logging" ], "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_1byte_test", + "name": "h2_ssl_test", "platforms": [ "windows", "linux", @@ -16469,18 +18368,19 @@ }, { "args": [ - "no_logging" + "no_op" ], "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_1byte_test", + "name": "h2_ssl_test", "platforms": [ "windows", "linux", @@ -16490,18 +18390,19 @@ }, { "args": [ - "no_op" + "payload" ], "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_1byte_test", + "name": "h2_ssl_test", "platforms": [ "windows", "linux", @@ -16511,18 +18412,19 @@ }, { "args": [ - "payload" + "ping" ], "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_1byte_test", + "name": "h2_ssl_test", "platforms": [ "windows", "linux", @@ -16537,13 +18439,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_1byte_test", + "name": "h2_ssl_test", "platforms": [ "windows", "linux", @@ -16558,13 +18461,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_1byte_test", + "name": "h2_ssl_test", "platforms": [ "windows", "linux", @@ -16579,13 +18483,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_1byte_test", + "name": "h2_ssl_test", "platforms": [ "windows", "linux", @@ -16600,13 +18505,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_1byte_test", + "name": "h2_ssl_test", "platforms": [ "windows", "linux", @@ -16621,13 +18527,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_1byte_test", + "name": "h2_ssl_test", "platforms": [ "windows", "linux", @@ -16642,13 +18549,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_1byte_test", + "name": "h2_ssl_test", "platforms": [ "windows", "linux", @@ -16663,13 +18571,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_1byte_test", + "name": "h2_ssl_test", "platforms": [ "windows", "linux", @@ -16684,13 +18593,36 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_1byte_test", + "name": "h2_ssl_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "simple_delayed_request" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "language": "c", + "name": "h2_ssl_test", "platforms": [ "windows", "linux", @@ -16705,13 +18637,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_1byte_test", + "name": "h2_ssl_test", "platforms": [ "windows", "linux", @@ -16726,13 +18659,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_1byte_test", + "name": "h2_ssl_test", "platforms": [ "windows", "linux", @@ -16747,13 +18681,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_1byte_test", + "name": "h2_ssl_test", "platforms": [ "windows", "linux", @@ -16768,13 +18703,14 @@ "ci_platforms": [ "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_sockpair_1byte_test", + "name": "h2_ssl_test", "platforms": [ "windows", "linux", @@ -16796,7 +18732,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_test", + "name": "h2_ssl_cert_test", "platforms": [ "windows", "linux", @@ -16818,7 +18754,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_test", + "name": "h2_ssl_cert_test", "platforms": [ "windows", "linux", @@ -16840,7 +18776,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_test", + "name": "h2_ssl_cert_test", "platforms": [ "windows", "linux", @@ -16862,7 +18798,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_test", + "name": "h2_ssl_cert_test", "platforms": [ "windows", "linux", @@ -16884,7 +18820,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_test", + "name": "h2_ssl_cert_test", "platforms": [ "windows", "linux", @@ -16906,7 +18842,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_test", + "name": "h2_ssl_cert_test", "platforms": [ "windows", "linux", @@ -16928,7 +18864,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_test", + "name": "h2_ssl_cert_test", "platforms": [ "windows", "linux", @@ -16950,7 +18886,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_test", + "name": "h2_ssl_cert_test", "platforms": [ "windows", "linux", @@ -16972,7 +18908,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_test", + "name": "h2_ssl_cert_test", "platforms": [ "windows", "linux", @@ -16994,7 +18930,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_test", + "name": "h2_ssl_cert_test", "platforms": [ "windows", "linux", @@ -17016,7 +18952,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_test", + "name": "h2_ssl_cert_test", "platforms": [ "windows", "linux", @@ -17038,7 +18974,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_test", + "name": "h2_ssl_cert_test", "platforms": [ "windows", "linux", @@ -17060,7 +18996,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_test", + "name": "h2_ssl_cert_test", "platforms": [ "windows", "linux", @@ -17082,7 +19018,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_test", + "name": "h2_ssl_cert_test", "platforms": [ "windows", "linux", @@ -17104,7 +19040,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_test", + "name": "h2_ssl_cert_test", "platforms": [ "windows", "linux", @@ -17126,7 +19062,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_test", + "name": "h2_ssl_cert_test", "platforms": [ "windows", "linux", @@ -17148,7 +19084,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_test", + "name": "h2_ssl_cert_test", "platforms": [ "windows", "linux", @@ -17170,7 +19106,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_test", + "name": "h2_ssl_cert_test", "platforms": [ "windows", "linux", @@ -17192,7 +19128,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_test", + "name": "h2_ssl_cert_test", "platforms": [ "windows", "linux", @@ -17214,7 +19150,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_test", + "name": "h2_ssl_cert_test", "platforms": [ "windows", "linux", @@ -17236,7 +19172,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_test", + "name": "h2_ssl_cert_test", "platforms": [ "windows", "linux", @@ -17258,7 +19194,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_test", + "name": "h2_ssl_cert_test", "platforms": [ "windows", "linux", @@ -17280,7 +19216,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_test", + "name": "h2_ssl_cert_test", "platforms": [ "windows", "linux", @@ -17302,7 +19238,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_test", + "name": "h2_ssl_cert_test", "platforms": [ "windows", "linux", @@ -17324,7 +19260,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_test", + "name": "h2_ssl_cert_test", "platforms": [ "windows", "linux", @@ -17346,7 +19282,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_test", + "name": "h2_ssl_cert_test", "platforms": [ "windows", "linux", @@ -17368,7 +19304,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_test", + "name": "h2_ssl_cert_test", "platforms": [ "windows", "linux", @@ -17390,7 +19326,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_test", + "name": "h2_ssl_cert_test", "platforms": [ "windows", "linux", @@ -17412,7 +19348,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_test", + "name": "h2_ssl_cert_test", "platforms": [ "windows", "linux", @@ -17434,7 +19370,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_test", + "name": "h2_ssl_cert_test", "platforms": [ "windows", "linux", @@ -17456,7 +19392,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_test", + "name": "h2_ssl_cert_test", "platforms": [ "windows", "linux", @@ -17478,7 +19414,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_test", + "name": "h2_ssl_cert_test", "platforms": [ "windows", "linux", @@ -17500,7 +19436,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_test", + "name": "h2_ssl_cert_test", "platforms": [ "windows", "linux", @@ -17522,7 +19458,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_test", + "name": "h2_ssl_cert_test", "platforms": [ "windows", "linux", @@ -17544,7 +19480,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_test", + "name": "h2_ssl_cert_test", "platforms": [ "windows", "linux", @@ -17566,7 +19502,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_test", + "name": "h2_ssl_cert_test", "platforms": [ "windows", "linux", @@ -17588,7 +19524,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_test", + "name": "h2_ssl_cert_test", "platforms": [ "windows", "linux", @@ -17610,7 +19546,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_test", + "name": "h2_ssl_cert_test", "platforms": [ "windows", "linux", @@ -17632,7 +19568,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_test", + "name": "h2_ssl_cert_test", "platforms": [ "windows", "linux", @@ -17654,7 +19590,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_test", + "name": "h2_ssl_cert_test", "platforms": [ "windows", "linux", @@ -17676,7 +19612,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_test", + "name": "h2_ssl_cert_test", "platforms": [ "windows", "linux", @@ -17698,7 +19634,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_test", + "name": "h2_ssl_cert_test", "platforms": [ "windows", "linux", @@ -17720,7 +19656,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_test", + "name": "h2_ssl_cert_test", "platforms": [ "windows", "linux", @@ -17742,7 +19678,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_test", + "name": "h2_ssl_cert_test", "platforms": [ "windows", "linux", @@ -17757,14 +19693,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_cert_test", + "name": "h2_ssl_proxy_test", "platforms": [ "windows", "linux", @@ -17779,14 +19714,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_cert_test", + "name": "h2_ssl_proxy_test", "platforms": [ "windows", "linux", @@ -17801,14 +19735,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_cert_test", + "name": "h2_ssl_proxy_test", "platforms": [ "windows", "linux", @@ -17823,14 +19756,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_cert_test", + "name": "h2_ssl_proxy_test", "platforms": [ "windows", "linux", @@ -17845,14 +19777,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_cert_test", + "name": "h2_ssl_proxy_test", "platforms": [ "windows", "linux", @@ -17867,14 +19798,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_cert_test", + "name": "h2_ssl_proxy_test", "platforms": [ "windows", "linux", @@ -17889,14 +19819,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_cert_test", + "name": "h2_ssl_proxy_test", "platforms": [ "windows", "linux", @@ -17911,14 +19840,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_cert_test", + "name": "h2_ssl_proxy_test", "platforms": [ "windows", "linux", @@ -17933,14 +19861,13 @@ "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_cert_test", + "name": "h2_ssl_proxy_test", "platforms": [ "windows", "linux", @@ -17950,41 +19877,18 @@ }, { "args": [ - "compressed_payload" + "default_host" ], "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_cert_test", - "platforms": [ - "windows", - "linux", - "mac", - "posix" - ] - }, - { - "args": [ - "connectivity" - ], - "ci_platforms": [ - "windows", - "linux", - "mac", - "posix" - ], - "cpu_cost": 0.1, - "exclude_configs": [], - "flaky": false, - "language": "c", - "name": "h2_ssl_cert_test", + "name": "h2_ssl_proxy_test", "platforms": [ "windows", "linux", @@ -17994,19 +19898,18 @@ }, { "args": [ - "default_host" + "disappearing_server" ], "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_cert_test", + "name": "h2_ssl_proxy_test", "platforms": [ "windows", "linux", @@ -18016,19 +19919,18 @@ }, { "args": [ - "disappearing_server" + "empty_batch" ], "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_cert_test", + "name": "h2_ssl_proxy_test", "platforms": [ "windows", "linux", @@ -18038,19 +19940,18 @@ }, { "args": [ - "empty_batch" + "filter_call_init_fails" ], "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_cert_test", + "name": "h2_ssl_proxy_test", "platforms": [ "windows", "linux", @@ -18060,19 +19961,18 @@ }, { "args": [ - "filter_call_init_fails" + "filter_causes_close" ], "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_cert_test", + "name": "h2_ssl_proxy_test", "platforms": [ "windows", "linux", @@ -18082,19 +19982,18 @@ }, { "args": [ - "filter_causes_close" + "graceful_server_shutdown" ], "ci_platforms": [ "windows", "linux", - "mac", "posix" ], - "cpu_cost": 1.0, + "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_cert_test", + "name": "h2_ssl_proxy_test", "platforms": [ "windows", "linux", @@ -18104,19 +20003,18 @@ }, { "args": [ - "graceful_server_shutdown" + "high_initial_seqno" ], "ci_platforms": [ "windows", "linux", - "mac", "posix" ], - "cpu_cost": 0.1, + "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_cert_test", + "name": "h2_ssl_proxy_test", "platforms": [ "windows", "linux", @@ -18126,19 +20024,18 @@ }, { "args": [ - "high_initial_seqno" + "idempotent_request" ], "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_cert_test", + "name": "h2_ssl_proxy_test", "platforms": [ "windows", "linux", @@ -18148,19 +20045,18 @@ }, { "args": [ - "hpack_size" + "invoke_large_request" ], "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_cert_test", + "name": "h2_ssl_proxy_test", "platforms": [ "windows", "linux", @@ -18170,19 +20066,18 @@ }, { "args": [ - "idempotent_request" + "large_metadata" ], "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_cert_test", + "name": "h2_ssl_proxy_test", "platforms": [ "windows", "linux", @@ -18192,19 +20087,18 @@ }, { "args": [ - "invoke_large_request" + "load_reporting_hook" ], "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_cert_test", + "name": "h2_ssl_proxy_test", "platforms": [ "windows", "linux", @@ -18214,19 +20108,18 @@ }, { "args": [ - "large_metadata" + "max_message_length" ], "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_cert_test", + "name": "h2_ssl_proxy_test", "platforms": [ "windows", "linux", @@ -18236,19 +20129,18 @@ }, { "args": [ - "load_reporting_hook" + "negative_deadline" ], "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_cert_test", + "name": "h2_ssl_proxy_test", "platforms": [ "windows", "linux", @@ -18258,19 +20150,18 @@ }, { "args": [ - "max_concurrent_streams" + "network_status_change" ], "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_cert_test", + "name": "h2_ssl_proxy_test", "platforms": [ "windows", "linux", @@ -18280,19 +20171,18 @@ }, { "args": [ - "max_message_length" + "no_logging" ], "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_cert_test", + "name": "h2_ssl_proxy_test", "platforms": [ "windows", "linux", @@ -18302,19 +20192,18 @@ }, { "args": [ - "negative_deadline" + "no_op" ], "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_cert_test", + "name": "h2_ssl_proxy_test", "platforms": [ "windows", "linux", @@ -18324,19 +20213,18 @@ }, { "args": [ - "network_status_change" + "payload" ], "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_cert_test", + "name": "h2_ssl_proxy_test", "platforms": [ "windows", "linux", @@ -18346,19 +20234,18 @@ }, { "args": [ - "no_logging" + "ping_pong_streaming" ], "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_cert_test", + "name": "h2_ssl_proxy_test", "platforms": [ "windows", "linux", @@ -18368,19 +20255,18 @@ }, { "args": [ - "no_op" + "registered_call" ], "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_cert_test", + "name": "h2_ssl_proxy_test", "platforms": [ "windows", "linux", @@ -18390,19 +20276,18 @@ }, { "args": [ - "payload" + "request_with_payload" ], "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_cert_test", + "name": "h2_ssl_proxy_test", "platforms": [ "windows", "linux", @@ -18412,19 +20297,18 @@ }, { "args": [ - "ping" + "server_finishes_request" ], "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_cert_test", + "name": "h2_ssl_proxy_test", "platforms": [ "windows", "linux", @@ -18434,19 +20318,18 @@ }, { "args": [ - "ping_pong_streaming" + "shutdown_finishes_calls" ], "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_cert_test", + "name": "h2_ssl_proxy_test", "platforms": [ "windows", "linux", @@ -18456,19 +20339,18 @@ }, { "args": [ - "registered_call" + "shutdown_finishes_tags" ], "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_cert_test", + "name": "h2_ssl_proxy_test", "platforms": [ "windows", "linux", @@ -18478,19 +20360,18 @@ }, { "args": [ - "request_with_flags" + "simple_cacheable_request" ], "ci_platforms": [ "windows", "linux", - "mac", "posix" ], - "cpu_cost": 0.1, + "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_cert_test", + "name": "h2_ssl_proxy_test", "platforms": [ "windows", "linux", @@ -18500,19 +20381,18 @@ }, { "args": [ - "request_with_payload" + "simple_delayed_request" ], "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_cert_test", + "name": "h2_ssl_proxy_test", "platforms": [ "windows", "linux", @@ -18522,19 +20402,18 @@ }, { "args": [ - "server_finishes_request" + "simple_metadata" ], "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_cert_test", + "name": "h2_ssl_proxy_test", "platforms": [ "windows", "linux", @@ -18544,19 +20423,18 @@ }, { "args": [ - "shutdown_finishes_calls" + "simple_request" ], "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_cert_test", + "name": "h2_ssl_proxy_test", "platforms": [ "windows", "linux", @@ -18566,19 +20444,18 @@ }, { "args": [ - "shutdown_finishes_tags" + "streaming_error_response" ], "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_cert_test", + "name": "h2_ssl_proxy_test", "platforms": [ "windows", "linux", @@ -18588,19 +20465,18 @@ }, { "args": [ - "simple_cacheable_request" + "trailing_metadata" ], "ci_platforms": [ "windows", "linux", - "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_cert_test", + "name": "h2_ssl_proxy_test", "platforms": [ "windows", "linux", @@ -18610,10 +20486,9 @@ }, { "args": [ - "simple_delayed_request" + "bad_hostname" ], "ci_platforms": [ - "windows", "linux", "mac", "posix" @@ -18622,9 +20497,8 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_cert_test", + "name": "h2_uds_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -18632,10 +20506,9 @@ }, { "args": [ - "simple_metadata" + "binary_metadata" ], "ci_platforms": [ - "windows", "linux", "mac", "posix" @@ -18644,9 +20517,8 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_cert_test", + "name": "h2_uds_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -18654,10 +20526,9 @@ }, { "args": [ - "simple_request" + "call_creds" ], "ci_platforms": [ - "windows", "linux", "mac", "posix" @@ -18666,9 +20537,8 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_cert_test", + "name": "h2_uds_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -18676,21 +20546,19 @@ }, { "args": [ - "streaming_error_response" + "cancel_after_accept" ], "ci_platforms": [ - "windows", "linux", "mac", "posix" ], - "cpu_cost": 1.0, + "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_cert_test", + "name": "h2_uds_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -18698,10 +20566,9 @@ }, { "args": [ - "trailing_metadata" + "cancel_after_client_done" ], "ci_platforms": [ - "windows", "linux", "mac", "posix" @@ -18710,9 +20577,8 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_cert_test", + "name": "h2_uds_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -18720,20 +20586,19 @@ }, { "args": [ - "bad_hostname" + "cancel_after_invoke" ], "ci_platforms": [ - "windows", "linux", + "mac", "posix" ], - "cpu_cost": 1.0, + "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_proxy_test", + "name": "h2_uds_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -18741,20 +20606,19 @@ }, { "args": [ - "binary_metadata" + "cancel_before_invoke" ], "ci_platforms": [ - "windows", "linux", + "mac", "posix" ], - "cpu_cost": 1.0, + "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_proxy_test", + "name": "h2_uds_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -18762,20 +20626,19 @@ }, { "args": [ - "call_creds" + "cancel_in_a_vacuum" ], "ci_platforms": [ - "windows", "linux", + "mac", "posix" ], - "cpu_cost": 1.0, + "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_proxy_test", + "name": "h2_uds_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -18783,20 +20646,19 @@ }, { "args": [ - "cancel_after_accept" + "cancel_with_status" ], "ci_platforms": [ - "windows", "linux", + "mac", "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_proxy_test", + "name": "h2_uds_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -18804,20 +20666,19 @@ }, { "args": [ - "cancel_after_client_done" + "compressed_payload" ], "ci_platforms": [ - "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_proxy_test", + "name": "h2_uds_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -18825,20 +20686,19 @@ }, { "args": [ - "cancel_after_invoke" + "connectivity" ], "ci_platforms": [ - "windows", "linux", + "mac", "posix" ], "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_proxy_test", + "name": "h2_uds_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -18846,20 +20706,19 @@ }, { "args": [ - "cancel_before_invoke" + "disappearing_server" ], "ci_platforms": [ - "windows", "linux", + "mac", "posix" ], - "cpu_cost": 0.1, + "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_proxy_test", + "name": "h2_uds_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -18867,20 +20726,19 @@ }, { "args": [ - "cancel_in_a_vacuum" + "empty_batch" ], "ci_platforms": [ - "windows", "linux", + "mac", "posix" ], - "cpu_cost": 0.1, + "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_proxy_test", + "name": "h2_uds_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -18888,20 +20746,19 @@ }, { "args": [ - "cancel_with_status" + "filter_call_init_fails" ], "ci_platforms": [ - "windows", "linux", + "mac", "posix" ], - "cpu_cost": 0.1, + "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_proxy_test", + "name": "h2_uds_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -18909,20 +20766,19 @@ }, { "args": [ - "default_host" + "filter_causes_close" ], "ci_platforms": [ - "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_proxy_test", + "name": "h2_uds_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -18930,20 +20786,19 @@ }, { "args": [ - "disappearing_server" + "graceful_server_shutdown" ], "ci_platforms": [ - "windows", "linux", + "mac", "posix" ], - "cpu_cost": 1.0, + "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_proxy_test", + "name": "h2_uds_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -18951,20 +20806,19 @@ }, { "args": [ - "empty_batch" + "high_initial_seqno" ], "ci_platforms": [ - "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_proxy_test", + "name": "h2_uds_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -18972,20 +20826,19 @@ }, { "args": [ - "filter_call_init_fails" + "hpack_size" ], "ci_platforms": [ - "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_proxy_test", + "name": "h2_uds_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -18993,20 +20846,19 @@ }, { "args": [ - "filter_causes_close" + "idempotent_request" ], "ci_platforms": [ - "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_proxy_test", + "name": "h2_uds_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -19014,20 +20866,19 @@ }, { "args": [ - "graceful_server_shutdown" + "invoke_large_request" ], "ci_platforms": [ - "windows", "linux", + "mac", "posix" ], - "cpu_cost": 0.1, + "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_proxy_test", + "name": "h2_uds_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -19035,20 +20886,19 @@ }, { "args": [ - "high_initial_seqno" + "large_metadata" ], "ci_platforms": [ - "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_proxy_test", + "name": "h2_uds_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -19056,20 +20906,19 @@ }, { "args": [ - "idempotent_request" + "load_reporting_hook" ], "ci_platforms": [ - "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_proxy_test", + "name": "h2_uds_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -19077,20 +20926,19 @@ }, { "args": [ - "invoke_large_request" + "max_concurrent_streams" ], "ci_platforms": [ - "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_proxy_test", + "name": "h2_uds_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -19098,20 +20946,19 @@ }, { "args": [ - "large_metadata" + "max_message_length" ], "ci_platforms": [ - "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_proxy_test", + "name": "h2_uds_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -19119,20 +20966,19 @@ }, { "args": [ - "load_reporting_hook" + "negative_deadline" ], "ci_platforms": [ - "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_proxy_test", + "name": "h2_uds_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -19140,20 +20986,19 @@ }, { "args": [ - "max_message_length" + "network_status_change" ], "ci_platforms": [ - "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_proxy_test", + "name": "h2_uds_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -19161,20 +21006,19 @@ }, { "args": [ - "negative_deadline" + "no_logging" ], "ci_platforms": [ - "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_proxy_test", + "name": "h2_uds_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -19182,20 +21026,19 @@ }, { "args": [ - "network_status_change" + "no_op" ], "ci_platforms": [ - "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_proxy_test", + "name": "h2_uds_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -19203,20 +21046,19 @@ }, { "args": [ - "no_logging" + "payload" ], "ci_platforms": [ - "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_proxy_test", + "name": "h2_uds_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -19224,20 +21066,19 @@ }, { "args": [ - "no_op" + "ping" ], "ci_platforms": [ - "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_proxy_test", + "name": "h2_uds_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -19245,20 +21086,19 @@ }, { "args": [ - "payload" + "ping_pong_streaming" ], "ci_platforms": [ - "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_proxy_test", + "name": "h2_uds_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -19266,20 +21106,19 @@ }, { "args": [ - "ping_pong_streaming" + "registered_call" ], "ci_platforms": [ - "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_proxy_test", + "name": "h2_uds_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -19287,20 +21126,19 @@ }, { "args": [ - "registered_call" + "request_with_flags" ], "ci_platforms": [ - "windows", "linux", + "mac", "posix" ], - "cpu_cost": 1.0, + "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_proxy_test", + "name": "h2_uds_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -19311,17 +21149,16 @@ "request_with_payload" ], "ci_platforms": [ - "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_proxy_test", + "name": "h2_uds_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -19332,17 +21169,16 @@ "server_finishes_request" ], "ci_platforms": [ - "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_proxy_test", + "name": "h2_uds_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -19353,17 +21189,16 @@ "shutdown_finishes_calls" ], "ci_platforms": [ - "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_proxy_test", + "name": "h2_uds_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -19374,17 +21209,16 @@ "shutdown_finishes_tags" ], "ci_platforms": [ - "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_proxy_test", + "name": "h2_uds_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -19395,17 +21229,16 @@ "simple_cacheable_request" ], "ci_platforms": [ - "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_proxy_test", + "name": "h2_uds_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -19416,17 +21249,16 @@ "simple_delayed_request" ], "ci_platforms": [ - "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_proxy_test", + "name": "h2_uds_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -19437,17 +21269,16 @@ "simple_metadata" ], "ci_platforms": [ - "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_proxy_test", + "name": "h2_uds_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -19458,17 +21289,16 @@ "simple_request" ], "ci_platforms": [ - "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_proxy_test", + "name": "h2_uds_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -19479,17 +21309,16 @@ "streaming_error_response" ], "ci_platforms": [ - "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_proxy_test", + "name": "h2_uds_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -19500,17 +21329,16 @@ "trailing_metadata" ], "ci_platforms": [ - "windows", "linux", + "mac", "posix" ], "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_ssl_proxy_test", + "name": "h2_uds_test", "platforms": [ - "windows", "linux", "mac", "posix" @@ -19521,6 +21349,7 @@ "bad_hostname" ], "ci_platforms": [ + "windows", "linux", "mac", "posix" @@ -19529,8 +21358,9 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_uds_test", + "name": "h2_census_nosec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -19541,6 +21371,7 @@ "binary_metadata" ], "ci_platforms": [ + "windows", "linux", "mac", "posix" @@ -19549,8 +21380,9 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_uds_test", + "name": "h2_census_nosec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -19558,19 +21390,21 @@ }, { "args": [ - "call_creds" + "cancel_after_accept" ], "ci_platforms": [ + "windows", "linux", "mac", "posix" ], - "cpu_cost": 1.0, + "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_uds_test", + "name": "h2_census_nosec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -19578,19 +21412,21 @@ }, { "args": [ - "cancel_after_accept" + "cancel_after_client_done" ], "ci_platforms": [ + "windows", "linux", "mac", "posix" ], - "cpu_cost": 0.1, + "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_uds_test", + "name": "h2_census_nosec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -19598,19 +21434,21 @@ }, { "args": [ - "cancel_after_client_done" + "cancel_after_invoke" ], "ci_platforms": [ + "windows", "linux", "mac", "posix" ], - "cpu_cost": 1.0, + "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_uds_test", + "name": "h2_census_nosec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -19618,9 +21456,10 @@ }, { "args": [ - "cancel_after_invoke" + "cancel_before_invoke" ], "ci_platforms": [ + "windows", "linux", "mac", "posix" @@ -19629,8 +21468,9 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_uds_test", + "name": "h2_census_nosec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -19638,9 +21478,10 @@ }, { "args": [ - "cancel_before_invoke" + "cancel_in_a_vacuum" ], "ci_platforms": [ + "windows", "linux", "mac", "posix" @@ -19649,8 +21490,9 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_uds_test", + "name": "h2_census_nosec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -19658,9 +21500,10 @@ }, { "args": [ - "cancel_in_a_vacuum" + "cancel_with_status" ], "ci_platforms": [ + "windows", "linux", "mac", "posix" @@ -19669,8 +21512,9 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_uds_test", + "name": "h2_census_nosec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -19678,19 +21522,21 @@ }, { "args": [ - "cancel_with_status" + "compressed_payload" ], "ci_platforms": [ + "windows", "linux", "mac", "posix" ], - "cpu_cost": 0.1, + "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_uds_test", + "name": "h2_census_nosec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -19698,19 +21544,21 @@ }, { "args": [ - "compressed_payload" + "connectivity" ], "ci_platforms": [ + "windows", "linux", "mac", "posix" ], - "cpu_cost": 1.0, + "cpu_cost": 0.1, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_uds_test", + "name": "h2_census_nosec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -19718,19 +21566,21 @@ }, { "args": [ - "connectivity" + "default_host" ], "ci_platforms": [ + "windows", "linux", "mac", "posix" ], - "cpu_cost": 0.1, + "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_uds_test", + "name": "h2_census_nosec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -19741,6 +21591,7 @@ "disappearing_server" ], "ci_platforms": [ + "windows", "linux", "mac", "posix" @@ -19749,8 +21600,9 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_uds_test", + "name": "h2_census_nosec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -19761,6 +21613,7 @@ "empty_batch" ], "ci_platforms": [ + "windows", "linux", "mac", "posix" @@ -19769,8 +21622,9 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_uds_test", + "name": "h2_census_nosec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -19781,6 +21635,7 @@ "filter_call_init_fails" ], "ci_platforms": [ + "windows", "linux", "mac", "posix" @@ -19789,8 +21644,9 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_uds_test", + "name": "h2_census_nosec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -19801,6 +21657,7 @@ "filter_causes_close" ], "ci_platforms": [ + "windows", "linux", "mac", "posix" @@ -19809,8 +21666,9 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_uds_test", + "name": "h2_census_nosec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -19821,6 +21679,7 @@ "graceful_server_shutdown" ], "ci_platforms": [ + "windows", "linux", "mac", "posix" @@ -19829,8 +21688,9 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_uds_test", + "name": "h2_census_nosec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -19841,6 +21701,7 @@ "high_initial_seqno" ], "ci_platforms": [ + "windows", "linux", "mac", "posix" @@ -19849,8 +21710,9 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_uds_test", + "name": "h2_census_nosec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -19861,6 +21723,7 @@ "hpack_size" ], "ci_platforms": [ + "windows", "linux", "mac", "posix" @@ -19869,8 +21732,9 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_uds_test", + "name": "h2_census_nosec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -19881,6 +21745,7 @@ "idempotent_request" ], "ci_platforms": [ + "windows", "linux", "mac", "posix" @@ -19889,8 +21754,9 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_uds_test", + "name": "h2_census_nosec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -19901,6 +21767,7 @@ "invoke_large_request" ], "ci_platforms": [ + "windows", "linux", "mac", "posix" @@ -19909,8 +21776,9 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_uds_test", + "name": "h2_census_nosec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -19921,6 +21789,7 @@ "large_metadata" ], "ci_platforms": [ + "windows", "linux", "mac", "posix" @@ -19929,8 +21798,9 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_uds_test", + "name": "h2_census_nosec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -19941,6 +21811,7 @@ "load_reporting_hook" ], "ci_platforms": [ + "windows", "linux", "mac", "posix" @@ -19949,8 +21820,9 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_uds_test", + "name": "h2_census_nosec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -19961,6 +21833,7 @@ "max_concurrent_streams" ], "ci_platforms": [ + "windows", "linux", "mac", "posix" @@ -19969,8 +21842,9 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_uds_test", + "name": "h2_census_nosec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -19981,6 +21855,7 @@ "max_message_length" ], "ci_platforms": [ + "windows", "linux", "mac", "posix" @@ -19989,8 +21864,9 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_uds_test", + "name": "h2_census_nosec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -20001,6 +21877,7 @@ "negative_deadline" ], "ci_platforms": [ + "windows", "linux", "mac", "posix" @@ -20009,8 +21886,9 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_uds_test", + "name": "h2_census_nosec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -20021,6 +21899,7 @@ "network_status_change" ], "ci_platforms": [ + "windows", "linux", "mac", "posix" @@ -20029,8 +21908,9 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_uds_test", + "name": "h2_census_nosec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -20041,6 +21921,7 @@ "no_logging" ], "ci_platforms": [ + "windows", "linux", "mac", "posix" @@ -20049,8 +21930,9 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_uds_test", + "name": "h2_census_nosec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -20061,6 +21943,7 @@ "no_op" ], "ci_platforms": [ + "windows", "linux", "mac", "posix" @@ -20069,8 +21952,9 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_uds_test", + "name": "h2_census_nosec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -20081,6 +21965,7 @@ "payload" ], "ci_platforms": [ + "windows", "linux", "mac", "posix" @@ -20089,8 +21974,9 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_uds_test", + "name": "h2_census_nosec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -20101,6 +21987,7 @@ "ping" ], "ci_platforms": [ + "windows", "linux", "mac", "posix" @@ -20109,8 +21996,9 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_uds_test", + "name": "h2_census_nosec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -20121,6 +22009,7 @@ "ping_pong_streaming" ], "ci_platforms": [ + "windows", "linux", "mac", "posix" @@ -20129,8 +22018,9 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_uds_test", + "name": "h2_census_nosec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -20141,6 +22031,7 @@ "registered_call" ], "ci_platforms": [ + "windows", "linux", "mac", "posix" @@ -20149,8 +22040,9 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_uds_test", + "name": "h2_census_nosec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -20161,6 +22053,7 @@ "request_with_flags" ], "ci_platforms": [ + "windows", "linux", "mac", "posix" @@ -20169,8 +22062,9 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_uds_test", + "name": "h2_census_nosec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -20181,6 +22075,7 @@ "request_with_payload" ], "ci_platforms": [ + "windows", "linux", "mac", "posix" @@ -20189,8 +22084,9 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_uds_test", + "name": "h2_census_nosec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -20201,6 +22097,7 @@ "server_finishes_request" ], "ci_platforms": [ + "windows", "linux", "mac", "posix" @@ -20209,8 +22106,9 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_uds_test", + "name": "h2_census_nosec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -20221,6 +22119,7 @@ "shutdown_finishes_calls" ], "ci_platforms": [ + "windows", "linux", "mac", "posix" @@ -20229,8 +22128,9 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_uds_test", + "name": "h2_census_nosec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -20241,6 +22141,7 @@ "shutdown_finishes_tags" ], "ci_platforms": [ + "windows", "linux", "mac", "posix" @@ -20249,8 +22150,9 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_uds_test", + "name": "h2_census_nosec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -20261,6 +22163,7 @@ "simple_cacheable_request" ], "ci_platforms": [ + "windows", "linux", "mac", "posix" @@ -20269,8 +22172,9 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_uds_test", + "name": "h2_census_nosec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -20281,6 +22185,7 @@ "simple_delayed_request" ], "ci_platforms": [ + "windows", "linux", "mac", "posix" @@ -20289,8 +22194,9 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_uds_test", + "name": "h2_census_nosec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -20301,6 +22207,7 @@ "simple_metadata" ], "ci_platforms": [ + "windows", "linux", "mac", "posix" @@ -20309,8 +22216,9 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_uds_test", + "name": "h2_census_nosec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -20321,6 +22229,7 @@ "simple_request" ], "ci_platforms": [ + "windows", "linux", "mac", "posix" @@ -20329,8 +22238,9 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_uds_test", + "name": "h2_census_nosec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -20341,6 +22251,7 @@ "streaming_error_response" ], "ci_platforms": [ + "windows", "linux", "mac", "posix" @@ -20349,8 +22260,9 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_uds_test", + "name": "h2_census_nosec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -20361,6 +22273,7 @@ "trailing_metadata" ], "ci_platforms": [ + "windows", "linux", "mac", "posix" @@ -20369,8 +22282,9 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_uds_test", + "name": "h2_census_nosec_test", "platforms": [ + "windows", "linux", "mac", "posix" @@ -20390,7 +22304,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_census_nosec_test", + "name": "h2_compress_nosec_test", "platforms": [ "windows", "linux", @@ -20412,7 +22326,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_census_nosec_test", + "name": "h2_compress_nosec_test", "platforms": [ "windows", "linux", @@ -20434,7 +22348,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_census_nosec_test", + "name": "h2_compress_nosec_test", "platforms": [ "windows", "linux", @@ -20456,7 +22370,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_census_nosec_test", + "name": "h2_compress_nosec_test", "platforms": [ "windows", "linux", @@ -20478,7 +22392,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_census_nosec_test", + "name": "h2_compress_nosec_test", "platforms": [ "windows", "linux", @@ -20500,7 +22414,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_census_nosec_test", + "name": "h2_compress_nosec_test", "platforms": [ "windows", "linux", @@ -20522,7 +22436,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_census_nosec_test", + "name": "h2_compress_nosec_test", "platforms": [ "windows", "linux", @@ -20544,7 +22458,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_census_nosec_test", + "name": "h2_compress_nosec_test", "platforms": [ "windows", "linux", @@ -20566,7 +22480,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_census_nosec_test", + "name": "h2_compress_nosec_test", "platforms": [ "windows", "linux", @@ -20588,7 +22502,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_census_nosec_test", + "name": "h2_compress_nosec_test", "platforms": [ "windows", "linux", @@ -20610,7 +22524,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_census_nosec_test", + "name": "h2_compress_nosec_test", "platforms": [ "windows", "linux", @@ -20632,7 +22546,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_census_nosec_test", + "name": "h2_compress_nosec_test", "platforms": [ "windows", "linux", @@ -20654,7 +22568,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_census_nosec_test", + "name": "h2_compress_nosec_test", "platforms": [ "windows", "linux", @@ -20676,7 +22590,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_census_nosec_test", + "name": "h2_compress_nosec_test", "platforms": [ "windows", "linux", @@ -20698,7 +22612,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_census_nosec_test", + "name": "h2_compress_nosec_test", "platforms": [ "windows", "linux", @@ -20720,7 +22634,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_census_nosec_test", + "name": "h2_compress_nosec_test", "platforms": [ "windows", "linux", @@ -20742,7 +22656,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_census_nosec_test", + "name": "h2_compress_nosec_test", "platforms": [ "windows", "linux", @@ -20764,7 +22678,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_census_nosec_test", + "name": "h2_compress_nosec_test", "platforms": [ "windows", "linux", @@ -20786,7 +22700,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_census_nosec_test", + "name": "h2_compress_nosec_test", "platforms": [ "windows", "linux", @@ -20808,7 +22722,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_census_nosec_test", + "name": "h2_compress_nosec_test", "platforms": [ "windows", "linux", @@ -20830,7 +22744,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_census_nosec_test", + "name": "h2_compress_nosec_test", "platforms": [ "windows", "linux", @@ -20852,7 +22766,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_census_nosec_test", + "name": "h2_compress_nosec_test", "platforms": [ "windows", "linux", @@ -20874,7 +22788,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_census_nosec_test", + "name": "h2_compress_nosec_test", "platforms": [ "windows", "linux", @@ -20896,7 +22810,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_census_nosec_test", + "name": "h2_compress_nosec_test", "platforms": [ "windows", "linux", @@ -20918,7 +22832,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_census_nosec_test", + "name": "h2_compress_nosec_test", "platforms": [ "windows", "linux", @@ -20940,7 +22854,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_census_nosec_test", + "name": "h2_compress_nosec_test", "platforms": [ "windows", "linux", @@ -20962,7 +22876,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_census_nosec_test", + "name": "h2_compress_nosec_test", "platforms": [ "windows", "linux", @@ -20984,7 +22898,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_census_nosec_test", + "name": "h2_compress_nosec_test", "platforms": [ "windows", "linux", @@ -21006,7 +22920,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_census_nosec_test", + "name": "h2_compress_nosec_test", "platforms": [ "windows", "linux", @@ -21028,7 +22942,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_census_nosec_test", + "name": "h2_compress_nosec_test", "platforms": [ "windows", "linux", @@ -21050,7 +22964,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_census_nosec_test", + "name": "h2_compress_nosec_test", "platforms": [ "windows", "linux", @@ -21072,7 +22986,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_census_nosec_test", + "name": "h2_compress_nosec_test", "platforms": [ "windows", "linux", @@ -21094,7 +23008,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_census_nosec_test", + "name": "h2_compress_nosec_test", "platforms": [ "windows", "linux", @@ -21116,7 +23030,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_census_nosec_test", + "name": "h2_compress_nosec_test", "platforms": [ "windows", "linux", @@ -21138,7 +23052,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_census_nosec_test", + "name": "h2_compress_nosec_test", "platforms": [ "windows", "linux", @@ -21160,7 +23074,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_census_nosec_test", + "name": "h2_compress_nosec_test", "platforms": [ "windows", "linux", @@ -21182,7 +23096,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_census_nosec_test", + "name": "h2_compress_nosec_test", "platforms": [ "windows", "linux", @@ -21204,7 +23118,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_census_nosec_test", + "name": "h2_compress_nosec_test", "platforms": [ "windows", "linux", @@ -21226,7 +23140,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_census_nosec_test", + "name": "h2_compress_nosec_test", "platforms": [ "windows", "linux", @@ -21248,7 +23162,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_census_nosec_test", + "name": "h2_compress_nosec_test", "platforms": [ "windows", "linux", @@ -21270,7 +23184,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_census_nosec_test", + "name": "h2_compress_nosec_test", "platforms": [ "windows", "linux", @@ -21292,7 +23206,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_census_nosec_test", + "name": "h2_compress_nosec_test", "platforms": [ "windows", "linux", @@ -21314,7 +23228,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_census_nosec_test", + "name": "h2_compress_nosec_test", "platforms": [ "windows", "linux", @@ -21336,7 +23250,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_compress_nosec_test", + "name": "h2_fake_resolver_nosec_test", "platforms": [ "windows", "linux", @@ -21358,7 +23272,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_compress_nosec_test", + "name": "h2_fake_resolver_nosec_test", "platforms": [ "windows", "linux", @@ -21380,7 +23294,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_compress_nosec_test", + "name": "h2_fake_resolver_nosec_test", "platforms": [ "windows", "linux", @@ -21402,7 +23316,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_compress_nosec_test", + "name": "h2_fake_resolver_nosec_test", "platforms": [ "windows", "linux", @@ -21424,7 +23338,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_compress_nosec_test", + "name": "h2_fake_resolver_nosec_test", "platforms": [ "windows", "linux", @@ -21446,7 +23360,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_compress_nosec_test", + "name": "h2_fake_resolver_nosec_test", "platforms": [ "windows", "linux", @@ -21468,7 +23382,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_compress_nosec_test", + "name": "h2_fake_resolver_nosec_test", "platforms": [ "windows", "linux", @@ -21490,7 +23404,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_compress_nosec_test", + "name": "h2_fake_resolver_nosec_test", "platforms": [ "windows", "linux", @@ -21512,7 +23426,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_compress_nosec_test", + "name": "h2_fake_resolver_nosec_test", "platforms": [ "windows", "linux", @@ -21534,7 +23448,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_compress_nosec_test", + "name": "h2_fake_resolver_nosec_test", "platforms": [ "windows", "linux", @@ -21556,7 +23470,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_compress_nosec_test", + "name": "h2_fake_resolver_nosec_test", "platforms": [ "windows", "linux", @@ -21578,7 +23492,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_compress_nosec_test", + "name": "h2_fake_resolver_nosec_test", "platforms": [ "windows", "linux", @@ -21600,7 +23514,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_compress_nosec_test", + "name": "h2_fake_resolver_nosec_test", "platforms": [ "windows", "linux", @@ -21622,7 +23536,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_compress_nosec_test", + "name": "h2_fake_resolver_nosec_test", "platforms": [ "windows", "linux", @@ -21644,7 +23558,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_compress_nosec_test", + "name": "h2_fake_resolver_nosec_test", "platforms": [ "windows", "linux", @@ -21666,7 +23580,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_compress_nosec_test", + "name": "h2_fake_resolver_nosec_test", "platforms": [ "windows", "linux", @@ -21688,7 +23602,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_compress_nosec_test", + "name": "h2_fake_resolver_nosec_test", "platforms": [ "windows", "linux", @@ -21710,7 +23624,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_compress_nosec_test", + "name": "h2_fake_resolver_nosec_test", "platforms": [ "windows", "linux", @@ -21732,7 +23646,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_compress_nosec_test", + "name": "h2_fake_resolver_nosec_test", "platforms": [ "windows", "linux", @@ -21754,7 +23668,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_compress_nosec_test", + "name": "h2_fake_resolver_nosec_test", "platforms": [ "windows", "linux", @@ -21776,7 +23690,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_compress_nosec_test", + "name": "h2_fake_resolver_nosec_test", "platforms": [ "windows", "linux", @@ -21798,7 +23712,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_compress_nosec_test", + "name": "h2_fake_resolver_nosec_test", "platforms": [ "windows", "linux", @@ -21820,7 +23734,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_compress_nosec_test", + "name": "h2_fake_resolver_nosec_test", "platforms": [ "windows", "linux", @@ -21842,7 +23756,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_compress_nosec_test", + "name": "h2_fake_resolver_nosec_test", "platforms": [ "windows", "linux", @@ -21864,7 +23778,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_compress_nosec_test", + "name": "h2_fake_resolver_nosec_test", "platforms": [ "windows", "linux", @@ -21886,7 +23800,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_compress_nosec_test", + "name": "h2_fake_resolver_nosec_test", "platforms": [ "windows", "linux", @@ -21908,7 +23822,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_compress_nosec_test", + "name": "h2_fake_resolver_nosec_test", "platforms": [ "windows", "linux", @@ -21930,7 +23844,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_compress_nosec_test", + "name": "h2_fake_resolver_nosec_test", "platforms": [ "windows", "linux", @@ -21952,7 +23866,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_compress_nosec_test", + "name": "h2_fake_resolver_nosec_test", "platforms": [ "windows", "linux", @@ -21974,7 +23888,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_compress_nosec_test", + "name": "h2_fake_resolver_nosec_test", "platforms": [ "windows", "linux", @@ -21996,7 +23910,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_compress_nosec_test", + "name": "h2_fake_resolver_nosec_test", "platforms": [ "windows", "linux", @@ -22018,7 +23932,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_compress_nosec_test", + "name": "h2_fake_resolver_nosec_test", "platforms": [ "windows", "linux", @@ -22040,7 +23954,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_compress_nosec_test", + "name": "h2_fake_resolver_nosec_test", "platforms": [ "windows", "linux", @@ -22062,7 +23976,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_compress_nosec_test", + "name": "h2_fake_resolver_nosec_test", "platforms": [ "windows", "linux", @@ -22084,7 +23998,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_compress_nosec_test", + "name": "h2_fake_resolver_nosec_test", "platforms": [ "windows", "linux", @@ -22106,7 +24020,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_compress_nosec_test", + "name": "h2_fake_resolver_nosec_test", "platforms": [ "windows", "linux", @@ -22128,7 +24042,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_compress_nosec_test", + "name": "h2_fake_resolver_nosec_test", "platforms": [ "windows", "linux", @@ -22150,7 +24064,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_compress_nosec_test", + "name": "h2_fake_resolver_nosec_test", "platforms": [ "windows", "linux", @@ -22172,7 +24086,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_compress_nosec_test", + "name": "h2_fake_resolver_nosec_test", "platforms": [ "windows", "linux", @@ -22194,7 +24108,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_compress_nosec_test", + "name": "h2_fake_resolver_nosec_test", "platforms": [ "windows", "linux", @@ -22216,7 +24130,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_compress_nosec_test", + "name": "h2_fake_resolver_nosec_test", "platforms": [ "windows", "linux", @@ -22238,7 +24152,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_compress_nosec_test", + "name": "h2_fake_resolver_nosec_test", "platforms": [ "windows", "linux", @@ -22260,7 +24174,7 @@ "exclude_configs": [], "flaky": false, "language": "c", - "name": "h2_compress_nosec_test", + "name": "h2_fake_resolver_nosec_test", "platforms": [ "windows", "linux", diff --git a/vsprojects/buildtests_c.sln b/vsprojects/buildtests_c.sln index 4345b9134db..54a3f7a6228 100644 --- a/vsprojects/buildtests_c.sln +++ b/vsprojects/buildtests_c.sln @@ -744,6 +744,30 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "h2_compress_test", "vcxproj {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "h2_fake_resolver_nosec_test", "vcxproj\test/end2end/fixtures\h2_fake_resolver_nosec_test\h2_fake_resolver_nosec_test.vcxproj", "{5C8F9B15-B0D0-54FE-1E54-A53F963D2B2F}" + ProjectSection(myProperties) = preProject + lib = "False" + EndProjectSection + ProjectSection(ProjectDependencies) = postProject + {47C2CB41-4E9F-58B6-F606-F6FAED5D00ED} = {47C2CB41-4E9F-58B6-F606-F6FAED5D00ED} + {0A7E7F92-FDEA-40F1-A9EC-3BA484F98BBF} = {0A7E7F92-FDEA-40F1-A9EC-3BA484F98BBF} + {46CEDFFF-9692-456A-AA24-38B5D6BCF4C5} = {46CEDFFF-9692-456A-AA24-38B5D6BCF4C5} + {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}") = "h2_fake_resolver_test", "vcxproj\test/end2end/fixtures\h2_fake_resolver_test\h2_fake_resolver_test.vcxproj", "{085ACF7D-D7CE-A9F1-576D-1AF901409FA4}" + ProjectSection(myProperties) = preProject + lib = "False" + EndProjectSection + ProjectSection(ProjectDependencies) = postProject + {1F1F9084-2A93-B80E-364F-5754894AFAB4} = {1F1F9084-2A93-B80E-364F-5754894AFAB4} + {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}") = "h2_fakesec_test", "vcxproj\test/end2end/fixtures\h2_fakesec_test\h2_fakesec_test.vcxproj", "{0E980562-3AA0-91B1-C590-85C9A899BE44}" ProjectSection(myProperties) = preProject lib = "False" @@ -2703,6 +2727,38 @@ Global {C7E516E9-B80F-4BC1-A617-095FC6E14BC9}.Release-DLL|Win32.Build.0 = Release|Win32 {C7E516E9-B80F-4BC1-A617-095FC6E14BC9}.Release-DLL|x64.ActiveCfg = Release|x64 {C7E516E9-B80F-4BC1-A617-095FC6E14BC9}.Release-DLL|x64.Build.0 = Release|x64 + {5C8F9B15-B0D0-54FE-1E54-A53F963D2B2F}.Debug|Win32.ActiveCfg = Debug|Win32 + {5C8F9B15-B0D0-54FE-1E54-A53F963D2B2F}.Debug|x64.ActiveCfg = Debug|x64 + {5C8F9B15-B0D0-54FE-1E54-A53F963D2B2F}.Release|Win32.ActiveCfg = Release|Win32 + {5C8F9B15-B0D0-54FE-1E54-A53F963D2B2F}.Release|x64.ActiveCfg = Release|x64 + {5C8F9B15-B0D0-54FE-1E54-A53F963D2B2F}.Debug|Win32.Build.0 = Debug|Win32 + {5C8F9B15-B0D0-54FE-1E54-A53F963D2B2F}.Debug|x64.Build.0 = Debug|x64 + {5C8F9B15-B0D0-54FE-1E54-A53F963D2B2F}.Release|Win32.Build.0 = Release|Win32 + {5C8F9B15-B0D0-54FE-1E54-A53F963D2B2F}.Release|x64.Build.0 = Release|x64 + {5C8F9B15-B0D0-54FE-1E54-A53F963D2B2F}.Debug-DLL|Win32.ActiveCfg = Debug|Win32 + {5C8F9B15-B0D0-54FE-1E54-A53F963D2B2F}.Debug-DLL|Win32.Build.0 = Debug|Win32 + {5C8F9B15-B0D0-54FE-1E54-A53F963D2B2F}.Debug-DLL|x64.ActiveCfg = Debug|x64 + {5C8F9B15-B0D0-54FE-1E54-A53F963D2B2F}.Debug-DLL|x64.Build.0 = Debug|x64 + {5C8F9B15-B0D0-54FE-1E54-A53F963D2B2F}.Release-DLL|Win32.ActiveCfg = Release|Win32 + {5C8F9B15-B0D0-54FE-1E54-A53F963D2B2F}.Release-DLL|Win32.Build.0 = Release|Win32 + {5C8F9B15-B0D0-54FE-1E54-A53F963D2B2F}.Release-DLL|x64.ActiveCfg = Release|x64 + {5C8F9B15-B0D0-54FE-1E54-A53F963D2B2F}.Release-DLL|x64.Build.0 = Release|x64 + {085ACF7D-D7CE-A9F1-576D-1AF901409FA4}.Debug|Win32.ActiveCfg = Debug|Win32 + {085ACF7D-D7CE-A9F1-576D-1AF901409FA4}.Debug|x64.ActiveCfg = Debug|x64 + {085ACF7D-D7CE-A9F1-576D-1AF901409FA4}.Release|Win32.ActiveCfg = Release|Win32 + {085ACF7D-D7CE-A9F1-576D-1AF901409FA4}.Release|x64.ActiveCfg = Release|x64 + {085ACF7D-D7CE-A9F1-576D-1AF901409FA4}.Debug|Win32.Build.0 = Debug|Win32 + {085ACF7D-D7CE-A9F1-576D-1AF901409FA4}.Debug|x64.Build.0 = Debug|x64 + {085ACF7D-D7CE-A9F1-576D-1AF901409FA4}.Release|Win32.Build.0 = Release|Win32 + {085ACF7D-D7CE-A9F1-576D-1AF901409FA4}.Release|x64.Build.0 = Release|x64 + {085ACF7D-D7CE-A9F1-576D-1AF901409FA4}.Debug-DLL|Win32.ActiveCfg = Debug|Win32 + {085ACF7D-D7CE-A9F1-576D-1AF901409FA4}.Debug-DLL|Win32.Build.0 = Debug|Win32 + {085ACF7D-D7CE-A9F1-576D-1AF901409FA4}.Debug-DLL|x64.ActiveCfg = Debug|x64 + {085ACF7D-D7CE-A9F1-576D-1AF901409FA4}.Debug-DLL|x64.Build.0 = Debug|x64 + {085ACF7D-D7CE-A9F1-576D-1AF901409FA4}.Release-DLL|Win32.ActiveCfg = Release|Win32 + {085ACF7D-D7CE-A9F1-576D-1AF901409FA4}.Release-DLL|Win32.Build.0 = Release|Win32 + {085ACF7D-D7CE-A9F1-576D-1AF901409FA4}.Release-DLL|x64.ActiveCfg = Release|x64 + {085ACF7D-D7CE-A9F1-576D-1AF901409FA4}.Release-DLL|x64.Build.0 = Release|x64 {0E980562-3AA0-91B1-C590-85C9A899BE44}.Debug|Win32.ActiveCfg = Debug|Win32 {0E980562-3AA0-91B1-C590-85C9A899BE44}.Debug|x64.ActiveCfg = Debug|x64 {0E980562-3AA0-91B1-C590-85C9A899BE44}.Release|Win32.ActiveCfg = Release|Win32 diff --git a/vsprojects/vcxproj/test/end2end/fixtures/h2_fake_resolver_nosec_test/h2_fake_resolver_nosec_test.vcxproj b/vsprojects/vcxproj/test/end2end/fixtures/h2_fake_resolver_nosec_test/h2_fake_resolver_nosec_test.vcxproj new file mode 100644 index 00000000000..3e5f60dcbac --- /dev/null +++ b/vsprojects/vcxproj/test/end2end/fixtures/h2_fake_resolver_nosec_test/h2_fake_resolver_nosec_test.vcxproj @@ -0,0 +1,191 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {5C8F9B15-B0D0-54FE-1E54-A53F963D2B2F} + true + $(SolutionDir)IntDir\$(MSBuildProjectName)\ + + + + v100 + + + v110 + + + v120 + + + v140 + + + Application + true + Unicode + + + Application + false + true + Unicode + + + + + + + + + + + + + h2_fake_resolver_nosec_test + static + Debug + + + h2_fake_resolver_nosec_test + 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 + + + + + + + + + + {47C2CB41-4E9F-58B6-F606-F6FAED5D00ED} + + + {0A7E7F92-FDEA-40F1-A9EC-3BA484F98BBF} + + + {46CEDFFF-9692-456A-AA24-38B5D6BCF4C5} + + + {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/end2end/fixtures/h2_fake_resolver_nosec_test/h2_fake_resolver_nosec_test.vcxproj.filters b/vsprojects/vcxproj/test/end2end/fixtures/h2_fake_resolver_nosec_test/h2_fake_resolver_nosec_test.vcxproj.filters new file mode 100644 index 00000000000..fa77558c9b6 --- /dev/null +++ b/vsprojects/vcxproj/test/end2end/fixtures/h2_fake_resolver_nosec_test/h2_fake_resolver_nosec_test.vcxproj.filters @@ -0,0 +1,24 @@ + + + + + test\core\end2end\fixtures + + + + + + {d16c806f-b9ed-2fc4-d125-d2f213d24e94} + + + {35eb96d1-e1d6-7d4f-1b67-58c90bbafc08} + + + {c8a16f5b-264e-c0f0-122b-295477b396f0} + + + {cd25af84-98e8-39f6-6af3-c1a852a54156} + + + + diff --git a/vsprojects/vcxproj/test/end2end/fixtures/h2_fake_resolver_test/h2_fake_resolver_test.vcxproj b/vsprojects/vcxproj/test/end2end/fixtures/h2_fake_resolver_test/h2_fake_resolver_test.vcxproj new file mode 100644 index 00000000000..a3977f1740d --- /dev/null +++ b/vsprojects/vcxproj/test/end2end/fixtures/h2_fake_resolver_test/h2_fake_resolver_test.vcxproj @@ -0,0 +1,202 @@ + + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {085ACF7D-D7CE-A9F1-576D-1AF901409FA4} + true + $(SolutionDir)IntDir\$(MSBuildProjectName)\ + + + + v100 + + + v110 + + + v120 + + + v140 + + + Application + true + Unicode + + + Application + false + true + Unicode + + + + + + + + + + + + + + h2_fake_resolver_test + static + Debug + static + Debug + + + h2_fake_resolver_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 + + + + + + + + + + {1F1F9084-2A93-B80E-364F-5754894AFAB4} + + + {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/end2end/fixtures/h2_fake_resolver_test/h2_fake_resolver_test.vcxproj.filters b/vsprojects/vcxproj/test/end2end/fixtures/h2_fake_resolver_test/h2_fake_resolver_test.vcxproj.filters new file mode 100644 index 00000000000..cb68d336f87 --- /dev/null +++ b/vsprojects/vcxproj/test/end2end/fixtures/h2_fake_resolver_test/h2_fake_resolver_test.vcxproj.filters @@ -0,0 +1,24 @@ + + + + + test\core\end2end\fixtures + + + + + + {3bb40091-0d52-0156-cc55-ce5f69e612a8} + + + {cac8fdf8-f489-f1ff-2812-79c47527b524} + + + {2fe5cc8d-2908-878f-3b45-50f8c2cfadea} + + + {f07f474f-9277-9b94-38b7-3f7d0c846fdb} + + + + From da091f7fa731f3dabd4cef10bd61d6d1835d960d Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Tue, 4 Oct 2016 10:39:19 -0700 Subject: [PATCH 16/48] Test setting max message size limits via service config. --- test/core/end2end/tests/max_message_length.c | 111 +++++++++++++------ 1 file changed, 77 insertions(+), 34 deletions(-) diff --git a/test/core/end2end/tests/max_message_length.c b/test/core/end2end/tests/max_message_length.c index 1dddb1a3d59..369bf10e46a 100644 --- a/test/core/end2end/tests/max_message_length.c +++ b/test/core/end2end/tests/max_message_length.c @@ -48,7 +48,8 @@ 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_channel_args *server_args, + const char *query_args) { grpc_end2end_test_fixture f; gpr_log(GPR_INFO, "%s/%s", test_name, config.name); // We intentionally do not pass the client and server args to @@ -56,7 +57,7 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config, // proxy, only on the backend server. f = config.create_fixture(NULL, NULL); config.init_server(&f, server_args); - config.init_client(&f, client_args, NULL); + config.init_client(&f, client_args, query_args); return f; } @@ -102,8 +103,10 @@ static void end_test(grpc_end2end_test_fixture *f) { // If send_limit is true, applies send limit on client; otherwise, applies // recv limit on server. static void test_max_message_length_on_request(grpc_end2end_test_config config, - bool send_limit) { - gpr_log(GPR_INFO, "testing request with send_limit=%d", send_limit); + bool send_limit, + bool use_service_config) { + gpr_log(GPR_INFO, "testing request with send_limit=%d use_service_config=%d", + send_limit, use_service_config); grpc_end2end_test_fixture f; grpc_arg channel_arg; @@ -127,21 +130,35 @@ static void test_max_message_length_on_request(grpc_end2end_test_config config, size_t details_capacity = 0; int was_cancelled = 2; - channel_arg.key = send_limit ? GRPC_ARG_MAX_SEND_MESSAGE_LENGTH - : GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH; - channel_arg.type = GRPC_ARG_INTEGER; - channel_arg.value.integer = 5; - - channel_args.num_args = 1; - channel_args.args = &channel_arg; + char *query_args = NULL; + grpc_channel_args *client_args = NULL; + grpc_channel_args *server_args = NULL; + if (use_service_config) { + // We don't currently support service configs on the server side. + GPR_ASSERT(send_limit); + query_args = "method_name=/service/method" + "&max_request_message_bytes=5"; + } else { + // Set limit via channel args. + channel_arg.key = send_limit ? GRPC_ARG_MAX_SEND_MESSAGE_LENGTH + : GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH; + channel_arg.type = GRPC_ARG_INTEGER; + channel_arg.value.integer = 5; + channel_args.num_args = 1; + channel_args.args = &channel_arg; + if (send_limit) { + client_args = &channel_args; + } else { + server_args = &channel_args; + } + } - f = begin_test(config, "test_max_message_length", - send_limit ? &channel_args : NULL, - send_limit ? NULL : &channel_args); + f = begin_test(config, "test_max_request_message_length", client_args, + server_args, query_args); cqv = cq_verifier_create(f.cq); c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, - "/foo", "foo.test.google.fr:1234", + "/service/method", "foo.test.google.fr:1234", gpr_inf_future(GPR_CLOCK_REALTIME), NULL); GPR_ASSERT(c); @@ -214,7 +231,7 @@ static void test_max_message_length_on_request(grpc_end2end_test_config config, CQ_EXPECT_COMPLETION(cqv, tag(1), 1); cq_verify(cqv); - GPR_ASSERT(0 == strcmp(call_details.method, "/foo")); + GPR_ASSERT(0 == strcmp(call_details.method, "/service/method")); GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr:1234")); GPR_ASSERT(was_cancelled == 1); @@ -246,8 +263,10 @@ done: // If send_limit is true, applies send limit on server; otherwise, applies // recv limit on client. static void test_max_message_length_on_response(grpc_end2end_test_config config, - bool send_limit) { - gpr_log(GPR_INFO, "testing response with send_limit=%d", send_limit); + bool send_limit, + bool use_service_config) { + gpr_log(GPR_INFO, "testing response with send_limit=%d use_service_config=%d", + send_limit, use_service_config); grpc_end2end_test_fixture f; grpc_arg channel_arg; @@ -272,21 +291,35 @@ static void test_max_message_length_on_response(grpc_end2end_test_config config, size_t details_capacity = 0; int was_cancelled = 2; - channel_arg.key = send_limit ? GRPC_ARG_MAX_SEND_MESSAGE_LENGTH - : GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH; - channel_arg.type = GRPC_ARG_INTEGER; - channel_arg.value.integer = 5; - - channel_args.num_args = 1; - channel_args.args = &channel_arg; + char *query_args = NULL; + grpc_channel_args *client_args = NULL; + grpc_channel_args *server_args = NULL; + if (use_service_config) { + // We don't currently support service configs on the server side. + GPR_ASSERT(!send_limit); + query_args = "method_name=/service/method" + "&max_response_message_bytes=5"; + } else { + // Set limit via channel args. + channel_arg.key = send_limit ? GRPC_ARG_MAX_SEND_MESSAGE_LENGTH + : GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH; + channel_arg.type = GRPC_ARG_INTEGER; + channel_arg.value.integer = 5; + channel_args.num_args = 1; + channel_args.args = &channel_arg; + if (send_limit) { + server_args = &channel_args; + } else { + client_args = &channel_args; + } + } - f = begin_test(config, "test_max_message_length", - send_limit ? NULL : &channel_args, - send_limit ? &channel_args : NULL); + f = begin_test(config, "test_max_response_message_length", client_args, + server_args, query_args); cqv = cq_verifier_create(f.cq); c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, - "/foo", "foo.test.google.fr:1234", + "/service/method", "foo.test.google.fr:1234", gpr_inf_future(GPR_CLOCK_REALTIME), NULL); GPR_ASSERT(c); @@ -365,7 +398,7 @@ static void test_max_message_length_on_response(grpc_end2end_test_config config, CQ_EXPECT_COMPLETION(cqv, tag(1), 1); cq_verify(cqv); - GPR_ASSERT(0 == strcmp(call_details.method, "/foo")); + GPR_ASSERT(0 == strcmp(call_details.method, "/service/method")); GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr:1234")); GPR_ASSERT(was_cancelled == 0); @@ -393,10 +426,20 @@ static void test_max_message_length_on_response(grpc_end2end_test_config config, } void max_message_length(grpc_end2end_test_config config) { - test_max_message_length_on_request(config, false /* send_limit */); - test_max_message_length_on_request(config, true /* send_limit */); - test_max_message_length_on_response(config, false /* send_limit */); - test_max_message_length_on_response(config, true /* send_limit */); + test_max_message_length_on_request(config, false /* send_limit */, + false /* use_service_config */); + test_max_message_length_on_request(config, true /* send_limit */, + false /* use_service_config */); + test_max_message_length_on_response(config, false /* send_limit */, + false /* use_service_config */); + test_max_message_length_on_response(config, true /* send_limit */, + false /* use_service_config */); + if (config.feature_mask & FEATURE_MASK_SUPPORTS_QUERY_ARGS) { + test_max_message_length_on_request(config, true /* send_limit */, + true /* use_service_config */); + test_max_message_length_on_response(config, false /* send_limit */, + true /* use_service_config */); + } } void max_message_length_pre_init(void) {} From 7c8b7564fc52d031bb9bc2700ea3135802f84bb8 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Wed, 5 Oct 2016 07:34:01 -0700 Subject: [PATCH 17/48] Update documentation for timer API. --- src/core/lib/iomgr/timer.h | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/core/lib/iomgr/timer.h b/src/core/lib/iomgr/timer.h index a825d2a28b1..5a9a1779631 100644 --- a/src/core/lib/iomgr/timer.h +++ b/src/core/lib/iomgr/timer.h @@ -49,11 +49,11 @@ typedef struct grpc_timer { } grpc_timer; /* Initialize *timer. When expired or canceled, timer_cb will be called with - *timer_cb_arg and status to indicate if it expired (SUCCESS) or was - canceled (CANCELLED). timer_cb is guaranteed to be called exactly once, - and application code should check the status to determine how it was - invoked. The application callback is also responsible for maintaining - information about when to free up any user-level state. */ + *timer_cb_arg and error set to indicate if it expired (GRPC_ERROR_NONE) or + was canceled (GRPC_ERROR_CANCELLED). timer_cb is guaranteed to be called + exactly once, and application code should check the error to determine + how it was invoked. The application callback is also responsible for + maintaining information about when to free up any user-level state. */ void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer, gpr_timespec deadline, grpc_iomgr_cb_func timer_cb, void *timer_cb_arg, gpr_timespec now); @@ -74,8 +74,8 @@ void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer, In all of these cases, the cancellation is still considered successful. They are essentially distinguished in that the timer_cb will be run - exactly once from either the cancellation (with status CANCELLED) - or from the activation (with status SUCCESS) + exactly once from either the cancellation (with error GRPC_ERROR_CANCELLED) + or from the activation (with error GRPC_ERROR_NONE). Note carefully that the callback function MAY occur in the same callstack as grpc_timer_cancel. It's expected that most timers will be cancelled (their @@ -83,14 +83,13 @@ void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer, that cancellation costs as little as possible. Making callbacks run inline matches this aim. - Requires: cancel() must happen after add() on a given timer */ + Requires: cancel() must happen after init() on a given timer */ void grpc_timer_cancel(grpc_exec_ctx *exec_ctx, grpc_timer *timer); /* iomgr internal api for dealing with timers */ /* Check for timers to be run, and run them. Return true if timer callbacks were executed. - Drops drop_mu if it is non-null before executing callbacks. If next is non-null, TRY to update *next with the next running timer IF that timer occurs before *next current value. *next is never guaranteed to be updated on any given execution; however, From e40dd29db6ceae42bd6dd68427d76ffa608bd404 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Wed, 5 Oct 2016 14:58:37 -0700 Subject: [PATCH 18/48] Handle the case where the resolver returns after the call is initialized. --- src/core/ext/client_config/client_channel.c | 164 +++++++++++++----- src/core/lib/channel/deadline_filter.c | 84 +++++---- src/core/lib/channel/deadline_filter.h | 34 +++- test/core/end2end/fake_resolver.c | 2 +- test/core/end2end/tests/cancel_after_accept.c | 41 ++++- 5 files changed, 236 insertions(+), 89 deletions(-) diff --git a/src/core/ext/client_config/client_channel.c b/src/core/ext/client_config/client_channel.c index fbe5a33f151..31789292390 100644 --- a/src/core/ext/client_config/client_channel.c +++ b/src/core/ext/client_config/client_channel.c @@ -444,16 +444,16 @@ typedef struct client_channel_call_data { // stack and each has its own mutex. If/when we have time, find a way // to avoid this without breaking the grpc_deadline_state abstraction. grpc_deadline_state deadline_state; - gpr_timespec deadline; + grpc_mdstr *path; // Request path. + gpr_timespec call_start_time; + gpr_timespec deadline; enum { WAIT_FOR_READY_UNSET, WAIT_FOR_READY_FALSE, WAIT_FOR_READY_TRUE } wait_for_ready_from_service_config; - - // Request path. - grpc_mdstr *path; + grpc_closure read_service_config; grpc_error *cancel_error; @@ -657,6 +657,20 @@ static bool pick_subchannel(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, int r; GRPC_LB_POLICY_REF(lb_policy, "pick_subchannel"); gpr_mu_unlock(&chand->mu); + // If the application explicitly set wait_for_ready, use that. + // Otherwise, if the service config specified a value for this + // method, use that. + gpr_mu_lock(&calld->mu); + if ((initial_metadata_flags & + GRPC_INITIAL_METADATA_WAIT_FOR_READY_EXPLICITLY_SET) == 0 && + calld->wait_for_ready_from_service_config != WAIT_FOR_READY_UNSET) { + if (calld->wait_for_ready_from_service_config == WAIT_FOR_READY_TRUE) { + initial_metadata_flags |= GRPC_INITIAL_METADATA_WAIT_FOR_READY; + } else { + initial_metadata_flags &= ~GRPC_INITIAL_METADATA_WAIT_FOR_READY; + } + } + gpr_mu_unlock(&calld->mu); // TODO(dgq): make this deadline configurable somehow. const grpc_lb_policy_pick_args inputs = { calld->pollent, initial_metadata, initial_metadata_flags, @@ -769,24 +783,12 @@ retry: calld->connected_subchannel == NULL && op->send_initial_metadata != NULL) { calld->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL; - // If the application explicitly set wait_for_ready, use that. - // Otherwise, if the service config specified a value for this - // method, use that. - uint32_t initial_metadata_flags = op->send_initial_metadata_flags; - if ((initial_metadata_flags & - GRPC_INITIAL_METADATA_WAIT_FOR_READY_EXPLICITLY_SET) == 0 && - calld->wait_for_ready_from_service_config != WAIT_FOR_READY_UNSET) { - if (calld->wait_for_ready_from_service_config == WAIT_FOR_READY_TRUE) { - initial_metadata_flags |= GRPC_INITIAL_METADATA_WAIT_FOR_READY; - } else { - initial_metadata_flags &= ~GRPC_INITIAL_METADATA_WAIT_FOR_READY; - } - } grpc_closure_init(&calld->next_step, subchannel_ready, calld); GRPC_CALL_STACK_REF(calld->owning_call, "pick_subchannel"); if (pick_subchannel(exec_ctx, elem, op->send_initial_metadata, - initial_metadata_flags, &calld->connected_subchannel, - &calld->next_step, GRPC_ERROR_NONE)) { + op->send_initial_metadata_flags, + &calld->connected_subchannel, &calld->next_step, + GRPC_ERROR_NONE)) { calld->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING; GRPC_CALL_STACK_UNREF(exec_ctx, calld->owning_call, "pick_subchannel"); } @@ -814,36 +816,69 @@ retry: GPR_TIMER_END("cc_start_transport_stream_op", 0); } -/* Constructor for call_data */ -static grpc_error *cc_init_call_elem(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem, - grpc_call_element_args *args) { +// Gets data from the service config. Invoked when the resolver returns +// its initial result. +static void read_service_config(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + grpc_call_element *elem = arg; channel_data *chand = elem->channel_data; call_data *calld = elem->call_data; + // If this is an error, there's no point in looking at the service config. + if (error != GRPC_ERROR_NONE) return; + // Get the method config table from channel data. gpr_mu_lock(&chand->mu); - grpc_method_config_table *method_config_table = - chand->method_config_table == NULL - ? NULL - : grpc_method_config_table_ref(chand->method_config_table); - gpr_mu_unlock(&chand->mu); - grpc_method_config *method_config = - method_config_table == NULL ? NULL - : grpc_method_config_table_get_method_config( - method_config_table, args->path); - grpc_deadline_state_init(exec_ctx, elem, args, method_config); - calld->wait_for_ready_from_service_config = WAIT_FOR_READY_UNSET; - if (method_config != NULL) { - bool *wait_for_ready = grpc_method_config_get_wait_for_ready(method_config); - if (wait_for_ready != NULL) { - calld->wait_for_ready_from_service_config = - *wait_for_ready ? WAIT_FOR_READY_TRUE : WAIT_FOR_READY_FALSE; - } + grpc_method_config_table *method_config_table = NULL; + if (chand->method_config_table != NULL) { + method_config_table = + grpc_method_config_table_ref(chand->method_config_table); } + gpr_mu_unlock(&chand->mu); + // If the method config table was present, use it. if (method_config_table != NULL) { + grpc_method_config *method_config = + grpc_method_config_table_get_method_config(method_config_table, + calld->path); + if (method_config != NULL) { + gpr_timespec *per_method_timeout = + grpc_method_config_get_timeout(method_config); + bool *wait_for_ready = + grpc_method_config_get_wait_for_ready(method_config); + if (per_method_timeout != NULL || wait_for_ready != NULL) { + gpr_mu_lock(&calld->mu); + if (per_method_timeout != NULL) { + gpr_timespec per_method_deadline = + gpr_time_add(calld->call_start_time, *per_method_timeout); + if (gpr_time_cmp(per_method_deadline, calld->deadline) < 0) { + calld->deadline = per_method_deadline; + // Reset deadline timer. + grpc_deadline_state_reset(exec_ctx, elem, calld->deadline); + } + } + if (wait_for_ready != NULL) { + calld->wait_for_ready_from_service_config = + *wait_for_ready ? WAIT_FOR_READY_TRUE : WAIT_FOR_READY_FALSE; + } + gpr_mu_unlock(&calld->mu); + } + } grpc_method_config_table_unref(method_config_table); } - calld->deadline = args->deadline; +} + +/* Constructor for call_data */ +static grpc_error *cc_init_call_elem(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem, + grpc_call_element_args *args) { + channel_data *chand = elem->channel_data; + call_data *calld = elem->call_data; + // Initialize data members. + grpc_deadline_state_init(exec_ctx, elem, args->call_stack); calld->path = GRPC_MDSTR_REF(args->path); + // TODO(roth): Is there a better value to use here for the actual start + // time of the call (i.e., something initialized at the surface layer)? + calld->call_start_time = gpr_now(GPR_CLOCK_MONOTONIC); + calld->deadline = gpr_convert_clock_type(args->deadline, GPR_CLOCK_MONOTONIC); + calld->wait_for_ready_from_service_config = WAIT_FOR_READY_UNSET; calld->cancel_error = GRPC_ERROR_NONE; gpr_atm_rel_store(&calld->subchannel_call, 0); gpr_mu_init(&calld->mu); @@ -854,6 +889,53 @@ static grpc_error *cc_init_call_elem(grpc_exec_ctx *exec_ctx, calld->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING; calld->owning_call = args->call_stack; calld->pollent = NULL; + // If the resolver has already returned results, then we can access + // the service config parameters immediately. Otherwise, we need to + // defer that work until the resolver returns an initial result. + // TODO(roth): This code is almost but not quite identical to the code + // in read_service_config() above. It would be nice to find a way to + // combine them, to avoid having to maintain it twice. + gpr_mu_lock(&chand->mu); + if (chand->lb_policy != NULL) { + // We already have a resolver result, so check for service config. + if (chand->method_config_table != NULL) { + grpc_method_config_table *method_config_table = + grpc_method_config_table_ref(chand->method_config_table); + gpr_mu_unlock(&chand->mu); + grpc_method_config *method_config = + grpc_method_config_table_get_method_config(method_config_table, + args->path); + if (method_config != NULL) { + gpr_timespec *per_method_timeout = + grpc_method_config_get_timeout(method_config); + if (per_method_timeout != NULL) { + gpr_timespec per_method_deadline = + gpr_time_add(calld->call_start_time, *per_method_timeout); + calld->deadline = gpr_time_min(calld->deadline, per_method_deadline); + } + bool *wait_for_ready = + grpc_method_config_get_wait_for_ready(method_config); + if (wait_for_ready != NULL) { + calld->wait_for_ready_from_service_config = + *wait_for_ready ? WAIT_FOR_READY_TRUE : WAIT_FOR_READY_FALSE; + } + } + grpc_method_config_table_unref(method_config_table); + } else { + gpr_mu_unlock(&chand->mu); + } + } else { + // We don't yet have a resolver result, so register a callback to + // get the service config data once the resolver returns. + grpc_closure_init(&calld->read_service_config, read_service_config, elem); + grpc_closure_list_append(&chand->waiting_for_config_closures, + &calld->read_service_config, GRPC_ERROR_NONE); + gpr_mu_unlock(&chand->mu); + } + // Start the deadline timer with the current deadline value. If we + // do not yet have service config data, then the timer may be reset + // later. + grpc_deadline_state_start(exec_ctx, elem, calld->deadline); return GRPC_ERROR_NONE; } diff --git a/src/core/lib/channel/deadline_filter.c b/src/core/lib/channel/deadline_filter.c index 5216338833d..d2ea5250f6c 100644 --- a/src/core/lib/channel/deadline_filter.c +++ b/src/core/lib/channel/deadline_filter.c @@ -64,30 +64,49 @@ static void timer_callback(grpc_exec_ctx* exec_ctx, void* arg, } // Starts the deadline timer. -static void start_timer_if_needed(grpc_exec_ctx* exec_ctx, - grpc_call_element* elem, - gpr_timespec deadline) { +static void start_timer_if_needed_locked(grpc_exec_ctx* exec_ctx, + grpc_call_element* elem, + gpr_timespec deadline) { grpc_deadline_state* deadline_state = elem->call_data; deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC); - if (gpr_time_cmp(deadline, gpr_inf_future(GPR_CLOCK_MONOTONIC)) != 0) { + // Note: We do not start the timer if there is already a timer + // pending. This should be okay, because this is only called from two + // functions exported by this module: grpc_deadline_state_start(), which + // starts the initial timer, and grpc_deadline_state_reset(), which + // cancels any pre-existing timer before starting a new one. In + // particular, we want to ensure that if grpc_deadline_state_start() + // winds up trying to start the timer after grpc_deadline_state_reset() + // has already done so, we ignore the value from the former. + if (!deadline_state->timer_pending && + gpr_time_cmp(deadline, gpr_inf_future(GPR_CLOCK_MONOTONIC)) != 0) { // Take a reference to the call stack, to be owned by the timer. GRPC_CALL_STACK_REF(deadline_state->call_stack, "deadline_timer"); - gpr_mu_lock(&deadline_state->timer_mu); deadline_state->timer_pending = true; grpc_timer_init(exec_ctx, &deadline_state->timer, deadline, timer_callback, elem, gpr_now(GPR_CLOCK_MONOTONIC)); - gpr_mu_unlock(&deadline_state->timer_mu); } } +static void start_timer_if_needed(grpc_exec_ctx* exec_ctx, + grpc_call_element* elem, + gpr_timespec deadline) { + grpc_deadline_state* deadline_state = elem->call_data; + gpr_mu_lock(&deadline_state->timer_mu); + start_timer_if_needed_locked(exec_ctx, elem, deadline); + gpr_mu_unlock(&deadline_state->timer_mu); +} // Cancels the deadline timer. -static void cancel_timer_if_needed(grpc_exec_ctx* exec_ctx, - grpc_deadline_state* deadline_state) { - gpr_mu_lock(&deadline_state->timer_mu); +static void cancel_timer_if_needed_locked(grpc_exec_ctx* exec_ctx, + grpc_deadline_state* deadline_state) { if (deadline_state->timer_pending) { grpc_timer_cancel(exec_ctx, &deadline_state->timer); deadline_state->timer_pending = false; } +} +static void cancel_timer_if_needed(grpc_exec_ctx* exec_ctx, + grpc_deadline_state* deadline_state) { + gpr_mu_lock(&deadline_state->timer_mu); + cancel_timer_if_needed_locked(exec_ctx, deadline_state); gpr_mu_unlock(&deadline_state->timer_mu); } @@ -108,6 +127,21 @@ static void inject_on_complete_cb(grpc_deadline_state* deadline_state, op->on_complete = &deadline_state->on_complete; } +void grpc_deadline_state_init(grpc_exec_ctx* exec_ctx, grpc_call_element* elem, + grpc_call_stack* call_stack) { + grpc_deadline_state* deadline_state = elem->call_data; + memset(deadline_state, 0, sizeof(*deadline_state)); + deadline_state->call_stack = call_stack; + gpr_mu_init(&deadline_state->timer_mu); +} + +void grpc_deadline_state_destroy(grpc_exec_ctx* exec_ctx, + grpc_call_element* elem) { + grpc_deadline_state* deadline_state = elem->call_data; + cancel_timer_if_needed(exec_ctx, deadline_state); + gpr_mu_destroy(&deadline_state->timer_mu); +} + // Callback and associated state for starting the timer after call stack // initialization has been completed. struct start_timer_after_init_state { @@ -122,24 +156,11 @@ static void start_timer_after_init(grpc_exec_ctx* exec_ctx, void* arg, gpr_free(state); } -void grpc_deadline_state_init(grpc_exec_ctx* exec_ctx, grpc_call_element* elem, - grpc_call_element_args* args, - grpc_method_config* method_config) { - grpc_deadline_state* deadline_state = elem->call_data; - memset(deadline_state, 0, sizeof(*deadline_state)); - deadline_state->call_stack = args->call_stack; - gpr_mu_init(&deadline_state->timer_mu); +void grpc_deadline_state_start(grpc_exec_ctx* exec_ctx, grpc_call_element* elem, + gpr_timespec deadline) { // Deadline will always be infinite on servers, so the timer will only be // set on clients with a finite deadline. - gpr_timespec deadline = - gpr_convert_clock_type(args->deadline, GPR_CLOCK_MONOTONIC); - if (method_config != NULL) { - gpr_timespec* per_method_deadline = - grpc_method_config_get_timeout(method_config); - if (per_method_deadline != NULL) { - deadline = gpr_time_min(deadline, *per_method_deadline); - } - } + deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC); if (gpr_time_cmp(deadline, gpr_inf_future(GPR_CLOCK_MONOTONIC)) != 0) { // When the deadline passes, we indicate the failure by sending down // an op with cancel_error set. However, we can't send down any ops @@ -156,11 +177,13 @@ void grpc_deadline_state_init(grpc_exec_ctx* exec_ctx, grpc_call_element* elem, } } -void grpc_deadline_state_destroy(grpc_exec_ctx* exec_ctx, - grpc_call_element* elem) { +void grpc_deadline_state_reset(grpc_exec_ctx* exec_ctx, grpc_call_element* elem, + gpr_timespec new_deadline) { grpc_deadline_state* deadline_state = elem->call_data; - cancel_timer_if_needed(exec_ctx, deadline_state); - gpr_mu_destroy(&deadline_state->timer_mu); + gpr_mu_lock(&deadline_state->timer_mu); + cancel_timer_if_needed_locked(exec_ctx, deadline_state); + start_timer_if_needed_locked(exec_ctx, elem, new_deadline); + gpr_mu_unlock(&deadline_state->timer_mu); } void grpc_deadline_state_client_start_transport_stream_op( @@ -217,7 +240,8 @@ static grpc_error* init_call_elem(grpc_exec_ctx* exec_ctx, grpc_call_element_args* args) { // Note: size of call data is different between client and server. memset(elem->call_data, 0, elem->filter->sizeof_call_data); - grpc_deadline_state_init(exec_ctx, elem, args, NULL /* method_config */); + grpc_deadline_state_init(exec_ctx, elem, args->call_stack); + grpc_deadline_state_start(exec_ctx, elem, args->deadline); return GRPC_ERROR_NONE; } diff --git a/src/core/lib/channel/deadline_filter.h b/src/core/lib/channel/deadline_filter.h index ce6e8ea974d..9fd38027215 100644 --- a/src/core/lib/channel/deadline_filter.h +++ b/src/core/lib/channel/deadline_filter.h @@ -56,19 +56,37 @@ typedef struct grpc_deadline_state { grpc_closure* next_on_complete; } grpc_deadline_state; -// To be used in a filter's init_call_elem(), destroy_call_elem(), and -// start_transport_stream_op() methods to enforce call deadlines. // -// REQUIRES: The first field in elem->call_data is a grpc_deadline_state. +// NOTE: All of these functions require that the first field in +// elem->call_data is a grpc_deadline_state. // -// For grpc_deadline_state_client_start_transport_stream_op(), it is the -// caller's responsibility to chain to the next filter if necessary -// after the function returns. + void grpc_deadline_state_init(grpc_exec_ctx* exec_ctx, grpc_call_element* elem, - grpc_call_element_args* args, - grpc_method_config* method_config); + grpc_call_stack* call_stack); void grpc_deadline_state_destroy(grpc_exec_ctx* exec_ctx, grpc_call_element* elem); + +// Starts the timer with the specified deadline. +// Should be called from the filter's init_call_elem() method. +void grpc_deadline_state_start(grpc_exec_ctx* exec_ctx, grpc_call_element* elem, + gpr_timespec deadline); + +// Cancels the existing timer and starts a new one with new_deadline. +// +// Note: It is generally safe to call this with an earlier deadline +// value than the current one, but not the reverse. No checks are done +// to ensure that the timer callback is not invoked while it is in the +// process of being reset, which means that attempting to increase the +// deadline may result in the timer being called twice. +void grpc_deadline_state_reset(grpc_exec_ctx* exec_ctx, grpc_call_element* elem, + gpr_timespec new_deadline); + +// To be called from the client-side filter's start_transport_stream_op() +// method. Ensures that the deadline timer is cancelled when the call +// is completed. +// +// Note: It is the caller's responsibility to chain to the next filter if +// necessary after this function returns. void grpc_deadline_state_client_start_transport_stream_op( grpc_exec_ctx* exec_ctx, grpc_call_element* elem, grpc_transport_stream_op* op); diff --git a/test/core/end2end/fake_resolver.c b/test/core/end2end/fake_resolver.c index cb5b9e52b7b..32dc9e2711d 100644 --- a/test/core/end2end/fake_resolver.c +++ b/test/core/end2end/fake_resolver.c @@ -203,7 +203,7 @@ static grpc_resolver* fake_resolver_create(grpc_resolver_factory* factory, const char* timeout_str = grpc_uri_get_query_arg(args->uri, "timeout_seconds"); gpr_timespec timeout = {timeout_str == NULL ? 0 : atoi(timeout_str), 0, - GPR_CLOCK_MONOTONIC}; + GPR_TIMESPAN}; const char* max_request_message_bytes_str = grpc_uri_get_query_arg(args->uri, "max_request_message_bytes"); int32_t max_request_message_bytes = diff --git a/test/core/end2end/tests/cancel_after_accept.c b/test/core/end2end/tests/cancel_after_accept.c index 8e2c9a0aa4b..9f498155271 100644 --- a/test/core/end2end/tests/cancel_after_accept.c +++ b/test/core/end2end/tests/cancel_after_accept.c @@ -49,12 +49,13 @@ 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_channel_args *server_args, + const char *query_args) { grpc_end2end_test_fixture f; gpr_log(GPR_INFO, "%s/%s", test_name, config.name); f = config.create_fixture(client_args, server_args); config.init_server(&f, server_args); - config.init_client(&f, client_args, NULL); + config.init_client(&f, client_args, query_args); return f; } @@ -98,15 +99,15 @@ static void end_test(grpc_end2end_test_fixture *f) { /* Cancel after accept, no payload */ static void test_cancel_after_accept(grpc_end2end_test_config config, - cancellation_mode mode) { + cancellation_mode mode, + bool use_service_config) { grpc_op ops[6]; grpc_op *op; grpc_call *c; grpc_call *s; - grpc_end2end_test_fixture f = - begin_test(config, "cancel_after_accept", NULL, NULL); - gpr_timespec deadline = five_seconds_time(); - cq_verifier *cqv = cq_verifier_create(f.cq); + gpr_timespec deadline = use_service_config + ? gpr_inf_future(GPR_CLOCK_MONOTONIC) + : five_seconds_time(); grpc_metadata_array initial_metadata_recv; grpc_metadata_array trailing_metadata_recv; grpc_metadata_array request_metadata_recv; @@ -125,8 +126,19 @@ static void test_cancel_after_accept(grpc_end2end_test_config config, grpc_raw_byte_buffer_create(&response_payload_slice, 1); int was_cancelled = 2; + const char *query_args = NULL; + if (use_service_config) { + query_args = + "method_name=/service/method" + "&timeout_seconds=5"; + } + grpc_end2end_test_fixture f = + begin_test(config, "cancel_after_accept", NULL, NULL, query_args); + cq_verifier *cqv = cq_verifier_create(f.cq); + c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, - "/foo", "foo.test.google.fr", deadline, NULL); + "/service/method", "foo.test.google.fr", + deadline, NULL); GPR_ASSERT(c); grpc_metadata_array_init(&initial_metadata_recv); @@ -230,7 +242,18 @@ void cancel_after_accept(grpc_end2end_test_config config) { unsigned i; for (i = 0; i < GPR_ARRAY_SIZE(cancellation_modes); i++) { - test_cancel_after_accept(config, cancellation_modes[i]); + test_cancel_after_accept(config, cancellation_modes[i], + false /* use_service_config */); + } + + if (config.feature_mask & FEATURE_MASK_SUPPORTS_QUERY_ARGS) { + for (i = 0; i < GPR_ARRAY_SIZE(cancellation_modes); i++) { + if (cancellation_modes[i].expect_status == + GRPC_STATUS_DEADLINE_EXCEEDED) { + test_cancel_after_accept(config, cancellation_modes[i], + true /* use_service_config */); + } + } } } From 81ae740e1eea8ba5b5cecf121900b9203a25ce8c Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Thu, 6 Oct 2016 08:38:48 -0700 Subject: [PATCH 19/48] Test setting wait_for_ready via service config. --- test/core/end2end/connection_refused_test.c | 31 ++++++++++++++++----- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/test/core/end2end/connection_refused_test.c b/test/core/end2end/connection_refused_test.c index 62278d63c5a..07d7010daad 100644 --- a/test/core/end2end/connection_refused_test.c +++ b/test/core/end2end/connection_refused_test.c @@ -37,14 +37,16 @@ #include #include #include +#include #include "test/core/end2end/cq_verifier.h" +#include "test/core/end2end/fake_resolver.h" #include "test/core/util/port.h" #include "test/core/util/test_config.h" static void *tag(intptr_t i) { return (void *)i; } -static void run_test(bool wait_for_ready) { +static void run_test(bool wait_for_ready, bool use_service_config) { grpc_channel *chan; grpc_call *call; gpr_timespec deadline = GRPC_TIMEOUT_SECONDS_TO_DEADLINE(2); @@ -57,8 +59,10 @@ static void run_test(bool wait_for_ready) { char *details = NULL; size_t details_capacity = 0; - gpr_log(GPR_INFO, "TEST: wait_for_ready=%d", wait_for_ready); + gpr_log(GPR_INFO, "TEST: wait_for_ready=%d use_service_config=%d", + wait_for_ready, use_service_config); + grpc_fake_resolver_init(); grpc_init(); grpc_metadata_array_init(&trailing_metadata_recv); @@ -69,11 +73,21 @@ static void run_test(bool wait_for_ready) { /* create a call, channel to a port which will refuse connection */ int port = grpc_pick_unused_port_or_die(); char *addr; - gpr_join_host_port(&addr, "localhost", port); + gpr_join_host_port(&addr, "127.0.0.1", port); + if (use_service_config) { + GPR_ASSERT(wait_for_ready); + char *server_uri; + gpr_asprintf(&server_uri, + "test:%s?method_name=/service/method&wait_for_ready=1", addr); + gpr_free(addr); + addr = server_uri; + } + gpr_log(GPR_INFO, "server: %s", addr); chan = grpc_insecure_channel_create(addr, NULL, NULL); call = grpc_channel_create_call(chan, NULL, GRPC_PROPAGATE_DEFAULTS, cq, - "/Foo", "nonexistant", deadline, NULL); + "/service/method", "nonexistant", deadline, + NULL); gpr_free(addr); @@ -81,7 +95,9 @@ static void run_test(bool wait_for_ready) { op = ops; op->op = GRPC_OP_SEND_INITIAL_METADATA; op->data.send_initial_metadata.count = 0; - op->flags = wait_for_ready ? GRPC_INITIAL_METADATA_WAIT_FOR_READY : 0; + op->flags = (wait_for_ready && !use_service_config) + ? GRPC_INITIAL_METADATA_WAIT_FOR_READY + : 0; op->reserved = NULL; op++; op->op = GRPC_OP_RECV_STATUS_ON_CLIENT; @@ -122,7 +138,8 @@ static void run_test(bool wait_for_ready) { int main(int argc, char **argv) { grpc_test_init(argc, argv); - run_test(false); - run_test(true); + run_test(false /* wait_for_ready */, false /* use_service_config */); + run_test(true /* wait_for_ready */, false /* use_service_config */); + run_test(true /* wait_for_ready */, true /* use_service_config */); return 0; } From 2623728cae4729b1059aed2c2b7cf4f49e8df22a Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Thu, 6 Oct 2016 08:54:59 -0700 Subject: [PATCH 20/48] Remove unnecessary include. --- src/core/lib/channel/deadline_filter.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/core/lib/channel/deadline_filter.h b/src/core/lib/channel/deadline_filter.h index 9fd38027215..716a8525653 100644 --- a/src/core/lib/channel/deadline_filter.h +++ b/src/core/lib/channel/deadline_filter.h @@ -35,8 +35,6 @@ #include "src/core/lib/channel/channel_stack.h" #include "src/core/lib/iomgr/timer.h" -#include "src/core/ext/client_config/method_config.h" - // State used for filters that enforce call deadlines. // Must be the first field in the filter's call_data. typedef struct grpc_deadline_state { From 8b4a70e3d33028286b4ae81ebf35e353a2056f8f Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Fri, 7 Oct 2016 07:33:30 -0700 Subject: [PATCH 21/48] Fix Windows build problem. --- src/core/ext/client_config/method_config.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/core/ext/client_config/method_config.c b/src/core/ext/client_config/method_config.c index 888b32c7f17..a112355ff5d 100644 --- a/src/core/ext/client_config/method_config.c +++ b/src/core/ext/client_config/method_config.c @@ -222,13 +222,17 @@ static const grpc_hash_table_vtable method_config_table_vtable = { grpc_method_config_table* grpc_method_config_table_create( size_t num_entries, grpc_method_config_table_entry* entries) { - grpc_hash_table_entry hash_table_entries[num_entries]; + grpc_hash_table_entry* hash_table_entries = + gpr_malloc(sizeof(grpc_hash_table_entry) * num_entries); for (size_t i = 0; i < num_entries; ++i) { hash_table_entries[i].key = entries[i].method_name; hash_table_entries[i].value = entries[i].method_config; hash_table_entries[i].vtable = &method_config_table_vtable; } - return grpc_hash_table_create(num_entries, hash_table_entries); + grpc_method_config_table* method_config_table = + grpc_hash_table_create(num_entries, hash_table_entries); + gpr_free(hash_table_entries); + return method_config_table; } grpc_method_config_table* grpc_method_config_table_ref( @@ -254,11 +258,12 @@ grpc_method_config* grpc_method_config_table_get_method_config( const char* path_str = grpc_mdstr_as_c_string(path); const char* sep = strrchr(path_str, '/') + 1; const size_t len = (size_t)(sep - path_str); - char buf[len + 2]; // '*' and NUL + char* buf = gpr_malloc(len + 2); // '*' and NUL memcpy(buf, path_str, len); buf[len] = '*'; buf[len + 1] = '\0'; grpc_mdstr* wildcard_path = grpc_mdstr_from_string(buf); + gpr_free(buf); method_config = grpc_hash_table_get(table, wildcard_path); GRPC_MDSTR_UNREF(wildcard_path); } From d8f4a124823c035f1550eb5275e644f08558bde4 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Fri, 7 Oct 2016 07:33:40 -0700 Subject: [PATCH 22/48] Fix build problem in test. --- test/core/end2end/fixtures/h2_ssl_cert.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/core/end2end/fixtures/h2_ssl_cert.c b/test/core/end2end/fixtures/h2_ssl_cert.c index c92464cd8b6..69d23fa22c7 100644 --- a/test/core/end2end/fixtures/h2_ssl_cert.c +++ b/test/core/end2end/fixtures/h2_ssl_cert.c @@ -267,7 +267,7 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config, gpr_log(GPR_INFO, "%s/%s", test_name, config.name); f = config.create_fixture(client_args, server_args); config.init_server(&f, server_args); - config.init_client(&f, client_args); + config.init_client(&f, client_args, NULL); return f; } From 9dab7d54a97f13e1f3a5884df9dcc9917d4da828 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Fri, 7 Oct 2016 07:48:03 -0700 Subject: [PATCH 23/48] Fix deadlock. --- src/core/ext/client_config/client_channel.c | 24 +++++++++++---------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/core/ext/client_config/client_channel.c b/src/core/ext/client_config/client_channel.c index 31789292390..6f2b32fb509 100644 --- a/src/core/ext/client_config/client_channel.c +++ b/src/core/ext/client_config/client_channel.c @@ -607,11 +607,16 @@ static void continue_picking(grpc_exec_ctx *exec_ctx, void *arg, /* cancelled, do nothing */ } else if (error != GRPC_ERROR_NONE) { grpc_exec_ctx_sched(exec_ctx, cpa->on_ready, GRPC_ERROR_REF(error), NULL); - } else if (pick_subchannel(exec_ctx, cpa->elem, cpa->initial_metadata, - cpa->initial_metadata_flags, - cpa->connected_subchannel, cpa->on_ready, - GRPC_ERROR_NONE)) { - grpc_exec_ctx_sched(exec_ctx, cpa->on_ready, GRPC_ERROR_NONE, NULL); + } else { + call_data *calld = cpa->elem->call_data; + gpr_mu_lock(&calld->mu); + if (pick_subchannel(exec_ctx, cpa->elem, cpa->initial_metadata, + cpa->initial_metadata_flags, + cpa->connected_subchannel, cpa->on_ready, + GRPC_ERROR_NONE)) { + grpc_exec_ctx_sched(exec_ctx, cpa->on_ready, GRPC_ERROR_NONE, NULL); + } + gpr_mu_unlock(&calld->mu); } gpr_free(cpa); } @@ -654,13 +659,11 @@ static bool pick_subchannel(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, GPR_ASSERT(error == GRPC_ERROR_NONE); if (chand->lb_policy != NULL) { grpc_lb_policy *lb_policy = chand->lb_policy; - int r; GRPC_LB_POLICY_REF(lb_policy, "pick_subchannel"); gpr_mu_unlock(&chand->mu); // If the application explicitly set wait_for_ready, use that. // Otherwise, if the service config specified a value for this // method, use that. - gpr_mu_lock(&calld->mu); if ((initial_metadata_flags & GRPC_INITIAL_METADATA_WAIT_FOR_READY_EXPLICITLY_SET) == 0 && calld->wait_for_ready_from_service_config != WAIT_FOR_READY_UNSET) { @@ -670,16 +673,15 @@ static bool pick_subchannel(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, initial_metadata_flags &= ~GRPC_INITIAL_METADATA_WAIT_FOR_READY; } } - gpr_mu_unlock(&calld->mu); // TODO(dgq): make this deadline configurable somehow. const grpc_lb_policy_pick_args inputs = { calld->pollent, initial_metadata, initial_metadata_flags, &calld->lb_token_mdelem, gpr_inf_future(GPR_CLOCK_MONOTONIC)}; - r = grpc_lb_policy_pick(exec_ctx, lb_policy, &inputs, connected_subchannel, - NULL, on_ready); + bool result = grpc_lb_policy_pick(exec_ctx, lb_policy, &inputs, + connected_subchannel, NULL, on_ready); GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "pick_subchannel"); GPR_TIMER_END("pick_subchannel", 0); - return r; + return result; } if (chand->resolver != NULL && !chand->started_resolving) { chand->started_resolving = true; From afae7217324da85cf351c00aedae8e3736bcbcda Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Fri, 7 Oct 2016 08:44:48 -0700 Subject: [PATCH 24/48] Fix test. --- test/core/channel/channel_stack_test.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/core/channel/channel_stack_test.c b/test/core/channel/channel_stack_test.c index b1c1ed9039e..df7dfe5c0b0 100644 --- a/test/core/channel/channel_stack_test.c +++ b/test/core/channel/channel_stack_test.c @@ -118,6 +118,7 @@ static void test_create_channel_stack(void) { int *channel_data; int *call_data; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_mdstr* path = grpc_mdstr_from_string("/service/method"); arg.type = GRPC_ARG_INTEGER; arg.key = "test_key"; @@ -137,7 +138,7 @@ static void test_create_channel_stack(void) { call_stack = gpr_malloc(channel_stack->call_stack_size); grpc_error *error = grpc_call_stack_init( &exec_ctx, channel_stack, 1, free_call, call_stack, NULL, NULL, - gpr_inf_future(GPR_CLOCK_MONOTONIC), call_stack); + path, gpr_inf_future(GPR_CLOCK_MONOTONIC), call_stack); GPR_ASSERT(error == GRPC_ERROR_NONE); GPR_ASSERT(call_stack->count == 1); call_elem = grpc_call_stack_element(call_stack, 0); @@ -154,6 +155,7 @@ static void test_create_channel_stack(void) { GRPC_CHANNEL_STACK_UNREF(&exec_ctx, channel_stack, "done"); grpc_exec_ctx_finish(&exec_ctx); + GRPC_MDSTR_UNREF(path); } int main(int argc, char **argv) { From fd2ddd28a974fe7d286d36e28a52a573623d25a2 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Fri, 7 Oct 2016 10:11:10 -0700 Subject: [PATCH 25/48] clang-format --- src/core/ext/client_config/client_channel.c | 5 +- test/core/channel/channel_stack_test.c | 6 +- test/core/end2end/end2end_tests.h | 3 +- test/core/end2end/fixtures/h2_ssl_cert.c | 70 ++++++++++---------- test/core/end2end/tests/max_message_length.c | 10 +-- 5 files changed, 47 insertions(+), 47 deletions(-) diff --git a/src/core/ext/client_config/client_channel.c b/src/core/ext/client_config/client_channel.c index 6f2b32fb509..0d243768ef2 100644 --- a/src/core/ext/client_config/client_channel.c +++ b/src/core/ext/client_config/client_channel.c @@ -611,9 +611,8 @@ static void continue_picking(grpc_exec_ctx *exec_ctx, void *arg, call_data *calld = cpa->elem->call_data; gpr_mu_lock(&calld->mu); if (pick_subchannel(exec_ctx, cpa->elem, cpa->initial_metadata, - cpa->initial_metadata_flags, - cpa->connected_subchannel, cpa->on_ready, - GRPC_ERROR_NONE)) { + cpa->initial_metadata_flags, cpa->connected_subchannel, + cpa->on_ready, GRPC_ERROR_NONE)) { grpc_exec_ctx_sched(exec_ctx, cpa->on_ready, GRPC_ERROR_NONE, NULL); } gpr_mu_unlock(&calld->mu); diff --git a/test/core/channel/channel_stack_test.c b/test/core/channel/channel_stack_test.c index df7dfe5c0b0..26fc3dc4a85 100644 --- a/test/core/channel/channel_stack_test.c +++ b/test/core/channel/channel_stack_test.c @@ -118,7 +118,7 @@ static void test_create_channel_stack(void) { int *channel_data; int *call_data; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - grpc_mdstr* path = grpc_mdstr_from_string("/service/method"); + grpc_mdstr *path = grpc_mdstr_from_string("/service/method"); arg.type = GRPC_ARG_INTEGER; arg.key = "test_key"; @@ -137,8 +137,8 @@ static void test_create_channel_stack(void) { call_stack = gpr_malloc(channel_stack->call_stack_size); grpc_error *error = grpc_call_stack_init( - &exec_ctx, channel_stack, 1, free_call, call_stack, NULL, NULL, - path, gpr_inf_future(GPR_CLOCK_MONOTONIC), call_stack); + &exec_ctx, channel_stack, 1, free_call, call_stack, NULL, NULL, path, + gpr_inf_future(GPR_CLOCK_MONOTONIC), call_stack); GPR_ASSERT(error == GRPC_ERROR_NONE); GPR_ASSERT(call_stack->count == 1); call_elem = grpc_call_stack_element(call_stack, 0); diff --git a/test/core/end2end/end2end_tests.h b/test/core/end2end/end2end_tests.h index 2230027a45e..e20273de90e 100644 --- a/test/core/end2end/end2end_tests.h +++ b/test/core/end2end/end2end_tests.h @@ -60,8 +60,7 @@ struct grpc_end2end_test_config { grpc_end2end_test_fixture (*create_fixture)(grpc_channel_args *client_args, grpc_channel_args *server_args); void (*init_client)(grpc_end2end_test_fixture *f, - grpc_channel_args *client_args, - const char *query_args); + grpc_channel_args *client_args, const char *query_args); void (*init_server)(grpc_end2end_test_fixture *f, grpc_channel_args *server_args); void (*tear_down_data)(grpc_end2end_test_fixture *f); diff --git a/test/core/end2end/fixtures/h2_ssl_cert.c b/test/core/end2end/fixtures/h2_ssl_cert.c index 69d23fa22c7..4c2f5f535e7 100644 --- a/test/core/end2end/fixtures/h2_ssl_cert.c +++ b/test/core/end2end/fixtures/h2_ssl_cert.c @@ -154,41 +154,41 @@ SERVER_INIT(GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY) typedef enum { NONE, SELF_SIGNED, SIGNED, BAD_CERT_PAIR } certtype; -#define CLIENT_INIT(cert_type) \ - static void CLIENT_INIT_NAME(cert_type)(grpc_end2end_test_fixture * f, \ - grpc_channel_args * client_args, \ - const char *query_args) { \ - GPR_ASSERT(query_args == NULL); \ - grpc_channel_credentials *ssl_creds = NULL; \ - grpc_ssl_pem_key_cert_pair self_signed_client_key_cert_pair = { \ - test_self_signed_client_key, test_self_signed_client_cert}; \ - grpc_ssl_pem_key_cert_pair signed_client_key_cert_pair = { \ - test_signed_client_key, test_signed_client_cert}; \ - grpc_ssl_pem_key_cert_pair bad_client_key_cert_pair = { \ - test_self_signed_client_key, test_signed_client_cert}; \ - grpc_ssl_pem_key_cert_pair *key_cert_pair = NULL; \ - switch (cert_type) { \ - case SELF_SIGNED: \ - key_cert_pair = &self_signed_client_key_cert_pair; \ - break; \ - case SIGNED: \ - key_cert_pair = &signed_client_key_cert_pair; \ - break; \ - case BAD_CERT_PAIR: \ - key_cert_pair = &bad_client_key_cert_pair; \ - break; \ - default: \ - break; \ - } \ - ssl_creds = \ - grpc_ssl_credentials_create(test_root_cert, key_cert_pair, NULL); \ - grpc_arg ssl_name_override = {GRPC_ARG_STRING, \ - GRPC_SSL_TARGET_NAME_OVERRIDE_ARG, \ - {"foo.test.google.fr"}}; \ - 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_creds); \ - grpc_channel_args_destroy(new_client_args); \ +#define CLIENT_INIT(cert_type) \ + static void CLIENT_INIT_NAME(cert_type)(grpc_end2end_test_fixture * f, \ + grpc_channel_args * client_args, \ + const char *query_args) { \ + GPR_ASSERT(query_args == NULL); \ + grpc_channel_credentials *ssl_creds = NULL; \ + grpc_ssl_pem_key_cert_pair self_signed_client_key_cert_pair = { \ + test_self_signed_client_key, test_self_signed_client_cert}; \ + grpc_ssl_pem_key_cert_pair signed_client_key_cert_pair = { \ + test_signed_client_key, test_signed_client_cert}; \ + grpc_ssl_pem_key_cert_pair bad_client_key_cert_pair = { \ + test_self_signed_client_key, test_signed_client_cert}; \ + grpc_ssl_pem_key_cert_pair *key_cert_pair = NULL; \ + switch (cert_type) { \ + case SELF_SIGNED: \ + key_cert_pair = &self_signed_client_key_cert_pair; \ + break; \ + case SIGNED: \ + key_cert_pair = &signed_client_key_cert_pair; \ + break; \ + case BAD_CERT_PAIR: \ + key_cert_pair = &bad_client_key_cert_pair; \ + break; \ + default: \ + break; \ + } \ + ssl_creds = \ + grpc_ssl_credentials_create(test_root_cert, key_cert_pair, NULL); \ + grpc_arg ssl_name_override = {GRPC_ARG_STRING, \ + GRPC_SSL_TARGET_NAME_OVERRIDE_ARG, \ + {"foo.test.google.fr"}}; \ + 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_creds); \ + grpc_channel_args_destroy(new_client_args); \ } CLIENT_INIT(NONE) diff --git a/test/core/end2end/tests/max_message_length.c b/test/core/end2end/tests/max_message_length.c index 369bf10e46a..e698987a0a4 100644 --- a/test/core/end2end/tests/max_message_length.c +++ b/test/core/end2end/tests/max_message_length.c @@ -136,8 +136,9 @@ static void test_max_message_length_on_request(grpc_end2end_test_config config, if (use_service_config) { // We don't currently support service configs on the server side. GPR_ASSERT(send_limit); - query_args = "method_name=/service/method" - "&max_request_message_bytes=5"; + query_args = + "method_name=/service/method" + "&max_request_message_bytes=5"; } else { // Set limit via channel args. channel_arg.key = send_limit ? GRPC_ARG_MAX_SEND_MESSAGE_LENGTH @@ -297,8 +298,9 @@ static void test_max_message_length_on_response(grpc_end2end_test_config config, if (use_service_config) { // We don't currently support service configs on the server side. GPR_ASSERT(!send_limit); - query_args = "method_name=/service/method" - "&max_response_message_bytes=5"; + query_args = + "method_name=/service/method" + "&max_response_message_bytes=5"; } else { // Set limit via channel args. channel_arg.key = send_limit ? GRPC_ARG_MAX_SEND_MESSAGE_LENGTH From 9db75cf68e23aecddc77fa825e4403131d29b276 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Fri, 7 Oct 2016 10:15:26 -0700 Subject: [PATCH 26/48] Revert changes to sockaddr_resolver_test, since we no longer support query_args there. --- .../resolvers/sockaddr_resolver_test.c | 84 +------------------ 1 file changed, 1 insertion(+), 83 deletions(-) diff --git a/test/core/client_config/resolvers/sockaddr_resolver_test.c b/test/core/client_config/resolvers/sockaddr_resolver_test.c index 3fc074adf30..b5d96efa1d9 100644 --- a/test/core/client_config/resolvers/sockaddr_resolver_test.c +++ b/test/core/client_config/resolvers/sockaddr_resolver_test.c @@ -37,21 +37,13 @@ #include #include -#include "src/core/ext/client_config/method_config.h" #include "src/core/ext/client_config/resolver_registry.h" #include "src/core/ext/client_config/resolver_result.h" -#include "src/core/lib/channel/channel_args.h" -#include "src/core/lib/transport/metadata.h" #include "test/core/util/test_config.h" typedef struct on_resolution_arg { char *expected_server_name; - const char *expected_method_name; - bool expected_wait_for_ready; - gpr_timespec expected_timeout; - int32_t expected_max_request_message_bytes; - int32_t expected_max_response_message_bytes; grpc_resolver_result *resolver_result; } on_resolution_arg; @@ -60,40 +52,6 @@ void on_resolution_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { const char *server_name = grpc_resolver_result_get_server_name(res->resolver_result); GPR_ASSERT(strcmp(res->expected_server_name, server_name) == 0); - const grpc_channel_args *lb_policy_args = - grpc_resolver_result_get_lb_policy_args(res->resolver_result); - if (res->expected_method_name == NULL) { - GPR_ASSERT(lb_policy_args == NULL); - } else { - const grpc_arg *channel_arg = - grpc_channel_args_find(lb_policy_args, GRPC_ARG_SERVICE_CONFIG); - GPR_ASSERT(channel_arg != NULL); - GPR_ASSERT(channel_arg->type == GRPC_ARG_POINTER); - grpc_method_config_table *method_config_table = - (grpc_method_config_table *)channel_arg->value.pointer.p; - GPR_ASSERT(method_config_table != NULL); - grpc_mdstr *path = grpc_mdstr_from_string(res->expected_method_name); - grpc_method_config *method_config = - grpc_method_config_table_get_method_config(method_config_table, path); - GRPC_MDSTR_UNREF(path); - GPR_ASSERT(method_config != NULL); - bool *wait_for_ready = grpc_method_config_get_wait_for_ready(method_config); - GPR_ASSERT(wait_for_ready != NULL); - GPR_ASSERT(*wait_for_ready == res->expected_wait_for_ready); - gpr_timespec *timeout = grpc_method_config_get_timeout(method_config); - GPR_ASSERT(timeout != NULL); - GPR_ASSERT(gpr_time_cmp(*timeout, res->expected_timeout) == 0); - int32_t *max_request_message_bytes = - grpc_method_config_get_max_request_message_bytes(method_config); - GPR_ASSERT(max_request_message_bytes != NULL); - GPR_ASSERT(*max_request_message_bytes == - res->expected_max_request_message_bytes); - int32_t *max_response_message_bytes = - grpc_method_config_get_max_response_message_bytes(method_config); - GPR_ASSERT(max_response_message_bytes != NULL); - GPR_ASSERT(*max_response_message_bytes == - res->expected_max_response_message_bytes); - } grpc_resolver_result_unref(exec_ctx, res->resolver_result); } @@ -109,43 +67,13 @@ static void test_succeeds(grpc_resolver_factory *factory, const char *string) { args.uri = uri; resolver = grpc_resolver_factory_create_resolver(factory, &args); GPR_ASSERT(resolver != NULL); - on_resolution_arg on_res_arg; - memset(&on_res_arg, 0, sizeof(on_res_arg)); - on_res_arg.expected_server_name = uri->path; - grpc_closure *on_resolution = - grpc_closure_create(on_resolution_cb, &on_res_arg); - grpc_resolver_next(&exec_ctx, resolver, &on_res_arg.resolver_result, - on_resolution); - GRPC_RESOLVER_UNREF(&exec_ctx, resolver, "test_succeeds"); - grpc_exec_ctx_finish(&exec_ctx); - grpc_uri_destroy(uri); -} -static void test_succeeds_with_service_config( - grpc_resolver_factory *factory, const char *string, const char *method_name, - bool wait_for_ready, gpr_timespec timeout, - int32_t max_request_message_bytes, int32_t max_response_message_bytes) { - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - grpc_uri *uri = grpc_uri_parse(string, 0); - grpc_resolver_args args; - grpc_resolver *resolver; - gpr_log(GPR_DEBUG, "test: '%s' should be valid for '%s'", string, - factory->vtable->scheme); - GPR_ASSERT(uri); - memset(&args, 0, sizeof(args)); - args.uri = uri; - resolver = grpc_resolver_factory_create_resolver(factory, &args); - GPR_ASSERT(resolver != NULL); on_resolution_arg on_res_arg; memset(&on_res_arg, 0, sizeof(on_res_arg)); on_res_arg.expected_server_name = uri->path; - on_res_arg.expected_method_name = method_name; - on_res_arg.expected_wait_for_ready = wait_for_ready; - on_res_arg.expected_timeout = timeout; - on_res_arg.expected_max_request_message_bytes = max_request_message_bytes; - on_res_arg.expected_max_response_message_bytes = max_response_message_bytes; grpc_closure *on_resolution = grpc_closure_create(on_resolution_cb, &on_res_arg); + grpc_resolver_next(&exec_ctx, resolver, &on_res_arg.resolver_result, on_resolution); GRPC_RESOLVER_UNREF(&exec_ctx, resolver, "test_succeeds"); @@ -191,16 +119,6 @@ int main(int argc, char **argv) { test_fails(ipv6, "ipv6:[::]:123456"); test_fails(ipv6, "ipv6:www.google.com"); - test_succeeds_with_service_config( - ipv4, - "ipv4:127.0.0.1:1234?method_name=/service/method" - "&wait_for_ready=1" - "&timeout_seconds=7" - "&max_request_message_bytes=456" - "&max_response_message_bytes=789", - "/service/method", true /* wait_for_ready */, - (gpr_timespec){7, 0, GPR_CLOCK_MONOTONIC}, 456, 789); - grpc_resolver_factory_unref(ipv4); grpc_resolver_factory_unref(ipv6); grpc_shutdown(); From 20d58ef12464f3a422b1afb99e6e62c8c9cf0d35 Mon Sep 17 00:00:00 2001 From: Jorge Canizales Date: Fri, 7 Oct 2016 19:44:03 -0700 Subject: [PATCH 27/48] Upgrade SwiftSample to XCode 8 and Swift 3 --- .../SwiftSample.xcodeproj/project.pbxproj | 18 +++++++++---- .../xcschemes/SwiftSample.xcscheme | 2 +- .../examples/SwiftSample/ViewController.swift | 25 +++++++++---------- 3 files changed, 26 insertions(+), 19 deletions(-) diff --git a/src/objective-c/examples/SwiftSample/SwiftSample.xcodeproj/project.pbxproj b/src/objective-c/examples/SwiftSample/SwiftSample.xcodeproj/project.pbxproj index afc3da71168..55b392e7783 100644 --- a/src/objective-c/examples/SwiftSample/SwiftSample.xcodeproj/project.pbxproj +++ b/src/objective-c/examples/SwiftSample/SwiftSample.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 48; objects = { /* Begin PBXBuildFile section */ @@ -123,16 +123,17 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0710; - LastUpgradeCheck = 0730; + LastUpgradeCheck = 0800; ORGANIZATIONNAME = gRPC; TargetAttributes = { 633BFFC11B950B210007E424 = { CreatedOnToolsVersion = 6.4; + LastSwiftMigration = 0800; }; }; }; buildConfigurationList = 633BFFBD1B950B210007E424 /* Build configuration list for PBXProject "SwiftSample" */; - compatibilityVersion = "Xcode 3.2"; + compatibilityVersion = "Xcode 8.0"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( @@ -246,8 +247,10 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -292,8 +295,10 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -312,6 +317,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 8.4; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; @@ -327,6 +333,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "io.grpc.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = ""; + SWIFT_VERSION = 3.0; USER_HEADER_SEARCH_PATHS = ""; }; name = Debug; @@ -341,6 +348,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "io.grpc.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = ""; + SWIFT_VERSION = 3.0; USER_HEADER_SEARCH_PATHS = ""; }; name = Release; @@ -355,7 +363,7 @@ 633BFFE01B950B210007E424 /* Release */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; + defaultConfigurationName = Debug; }; 633BFFE11B950B210007E424 /* Build configuration list for PBXNativeTarget "SwiftSample" */ = { isa = XCConfigurationList; @@ -364,7 +372,7 @@ 633BFFE31B950B210007E424 /* Release */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; + defaultConfigurationName = Debug; }; /* End XCConfigurationList section */ }; diff --git a/src/objective-c/examples/SwiftSample/SwiftSample.xcodeproj/xcshareddata/xcschemes/SwiftSample.xcscheme b/src/objective-c/examples/SwiftSample/SwiftSample.xcodeproj/xcshareddata/xcschemes/SwiftSample.xcscheme index bba6a02b2b4..87bca5ec681 100644 --- a/src/objective-c/examples/SwiftSample/SwiftSample.xcodeproj/xcshareddata/xcschemes/SwiftSample.xcscheme +++ b/src/objective-c/examples/SwiftSample/SwiftSample.xcodeproj/xcshareddata/xcschemes/SwiftSample.xcscheme @@ -1,6 +1,6 @@ Date: Fri, 7 Oct 2016 19:47:03 -0700 Subject: [PATCH 28/48] Update Sample project to XCode 8 --- .../examples/Sample/Sample.xcodeproj/project.pbxproj | 12 +++++++++--- .../xcshareddata/xcschemes/Sample.xcscheme | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/objective-c/examples/Sample/Sample.xcodeproj/project.pbxproj b/src/objective-c/examples/Sample/Sample.xcodeproj/project.pbxproj index ab7159cda2f..8d34b26c4fc 100644 --- a/src/objective-c/examples/Sample/Sample.xcodeproj/project.pbxproj +++ b/src/objective-c/examples/Sample/Sample.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 48; objects = { /* Begin PBXBuildFile section */ @@ -129,7 +129,7 @@ 6369A2621A9322E20015FC5C /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0730; + LastUpgradeCheck = 0800; ORGANIZATIONNAME = gRPC; TargetAttributes = { 6369A2691A9322E20015FC5C = { @@ -138,7 +138,7 @@ }; }; buildConfigurationList = 6369A2651A9322E20015FC5C /* Build configuration list for PBXProject "Sample" */; - compatibilityVersion = "Xcode 3.2"; + compatibilityVersion = "Xcode 8.0"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( @@ -253,8 +253,10 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -263,6 +265,7 @@ ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", @@ -296,8 +299,10 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -305,6 +310,7 @@ ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; diff --git a/src/objective-c/examples/Sample/Sample.xcodeproj/xcshareddata/xcschemes/Sample.xcscheme b/src/objective-c/examples/Sample/Sample.xcodeproj/xcshareddata/xcschemes/Sample.xcscheme index d399e22e460..881474b111c 100644 --- a/src/objective-c/examples/Sample/Sample.xcodeproj/xcshareddata/xcschemes/Sample.xcscheme +++ b/src/objective-c/examples/Sample/Sample.xcodeproj/xcshareddata/xcschemes/Sample.xcscheme @@ -1,6 +1,6 @@ Date: Mon, 10 Oct 2016 01:40:09 -0700 Subject: [PATCH 29/48] Wakeup fds on bad poll --- src/core/lib/iomgr/ev_poll_posix.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/core/lib/iomgr/ev_poll_posix.c b/src/core/lib/iomgr/ev_poll_posix.c index 16a5e3083e6..3de329c645d 100644 --- a/src/core/lib/iomgr/ev_poll_posix.c +++ b/src/core/lib/iomgr/ev_poll_posix.c @@ -961,8 +961,16 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, if (errno != EINTR) { work_combine_error(&error, GRPC_OS_ERROR(errno, "poll")); } + for (i = 2; i < pfd_count; i++) { - fd_end_poll(exec_ctx, &watchers[i], 0, 0, NULL); + if (watchers[i].fd == NULL) { + fd_end_poll(exec_ctx, &watchers[i], 0, 0, NULL); + } else { + // Wake up all the file descriptors, if we have an invalid one + // we can identify it on the next pollset_work() + fd_end_poll(exec_ctx, &watchers[i], POLLIN_CHECK, POLLOUT_CHECK, + pollset); + } } } else if (r == 0) { for (i = 2; i < pfd_count; i++) { From c1c38586dedfb4368372a2de03df1645a2a9ee7f Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Tue, 11 Oct 2016 11:03:27 -0700 Subject: [PATCH 30/48] Code review changes. --- src/core/ext/client_config/client_channel.c | 25 ++++++++++++--------- src/core/ext/client_config/method_config.c | 25 +++++++++++---------- src/core/ext/client_config/method_config.h | 24 +++++++++++--------- src/core/lib/channel/message_size_filter.c | 4 ++-- src/core/lib/transport/hashtable.c | 9 ++++---- src/core/lib/transport/hashtable.h | 5 +++-- 6 files changed, 51 insertions(+), 41 deletions(-) diff --git a/src/core/ext/client_config/client_channel.c b/src/core/ext/client_config/client_channel.c index 0d243768ef2..0594c0b3aca 100644 --- a/src/core/ext/client_config/client_channel.c +++ b/src/core/ext/client_config/client_channel.c @@ -663,9 +663,13 @@ static bool pick_subchannel(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, // If the application explicitly set wait_for_ready, use that. // Otherwise, if the service config specified a value for this // method, use that. - if ((initial_metadata_flags & - GRPC_INITIAL_METADATA_WAIT_FOR_READY_EXPLICITLY_SET) == 0 && - calld->wait_for_ready_from_service_config != WAIT_FOR_READY_UNSET) { + const bool wait_for_ready_set_from_api = + initial_metadata_flags & + GRPC_INITIAL_METADATA_WAIT_FOR_READY_EXPLICITLY_SET; + const bool wait_for_ready_set_from_service_config = + calld->wait_for_ready_from_service_config != WAIT_FOR_READY_UNSET; + if (!wait_for_ready_set_from_api && + wait_for_ready_set_from_service_config) { if (calld->wait_for_ready_from_service_config == WAIT_FOR_READY_TRUE) { initial_metadata_flags |= GRPC_INITIAL_METADATA_WAIT_FOR_READY; } else { @@ -676,8 +680,9 @@ static bool pick_subchannel(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, const grpc_lb_policy_pick_args inputs = { calld->pollent, initial_metadata, initial_metadata_flags, &calld->lb_token_mdelem, gpr_inf_future(GPR_CLOCK_MONOTONIC)}; - bool result = grpc_lb_policy_pick(exec_ctx, lb_policy, &inputs, - connected_subchannel, NULL, on_ready); + const bool result = + grpc_lb_policy_pick(exec_ctx, lb_policy, &inputs, + connected_subchannel, NULL, on_ready); GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "pick_subchannel"); GPR_TIMER_END("pick_subchannel", 0); return result; @@ -836,13 +841,13 @@ static void read_service_config(grpc_exec_ctx *exec_ctx, void *arg, gpr_mu_unlock(&chand->mu); // If the method config table was present, use it. if (method_config_table != NULL) { - grpc_method_config *method_config = + const grpc_method_config *method_config = grpc_method_config_table_get_method_config(method_config_table, calld->path); if (method_config != NULL) { - gpr_timespec *per_method_timeout = + const gpr_timespec *per_method_timeout = grpc_method_config_get_timeout(method_config); - bool *wait_for_ready = + const bool *wait_for_ready = grpc_method_config_get_wait_for_ready(method_config); if (per_method_timeout != NULL || wait_for_ready != NULL) { gpr_mu_lock(&calld->mu); @@ -907,14 +912,14 @@ static grpc_error *cc_init_call_elem(grpc_exec_ctx *exec_ctx, grpc_method_config_table_get_method_config(method_config_table, args->path); if (method_config != NULL) { - gpr_timespec *per_method_timeout = + const gpr_timespec *per_method_timeout = grpc_method_config_get_timeout(method_config); if (per_method_timeout != NULL) { gpr_timespec per_method_deadline = gpr_time_add(calld->call_start_time, *per_method_timeout); calld->deadline = gpr_time_min(calld->deadline, per_method_deadline); } - bool *wait_for_ready = + const bool *wait_for_ready = grpc_method_config_get_wait_for_ready(method_config); if (wait_for_ready != NULL) { calld->wait_for_ready_from_service_config = diff --git a/src/core/ext/client_config/method_config.c b/src/core/ext/client_config/method_config.c index a112355ff5d..3699c22810a 100644 --- a/src/core/ext/client_config/method_config.c +++ b/src/core/ext/client_config/method_config.c @@ -174,29 +174,30 @@ void grpc_method_config_unref(grpc_method_config* method_config) { } } -int grpc_method_config_cmp(grpc_method_config* method_config1, - grpc_method_config* method_config2) { +int grpc_method_config_cmp(const grpc_method_config* method_config1, + const grpc_method_config* method_config2) { return grpc_hash_table_cmp(method_config1->table, method_config2->table); } -bool* grpc_method_config_get_wait_for_ready(grpc_method_config* method_config) { +const bool* grpc_method_config_get_wait_for_ready( + const grpc_method_config* method_config) { return grpc_hash_table_get(method_config->table, method_config->wait_for_ready_key); } -gpr_timespec* grpc_method_config_get_timeout( - grpc_method_config* method_config) { +const gpr_timespec* grpc_method_config_get_timeout( + const grpc_method_config* method_config) { return grpc_hash_table_get(method_config->table, method_config->timeout_key); } -int32_t* grpc_method_config_get_max_request_message_bytes( - grpc_method_config* method_config) { +const int32_t* grpc_method_config_get_max_request_message_bytes( + const grpc_method_config* method_config) { return grpc_hash_table_get(method_config->table, method_config->max_request_message_bytes_key); } -int32_t* grpc_method_config_get_max_response_message_bytes( - grpc_method_config* method_config) { +const int32_t* grpc_method_config_get_max_response_message_bytes( + const grpc_method_config* method_config) { return grpc_hash_table_get(method_config->table, method_config->max_response_message_bytes_key); } @@ -244,13 +245,13 @@ void grpc_method_config_table_unref(grpc_method_config_table* table) { grpc_hash_table_unref(table); } -int grpc_method_config_table_cmp(grpc_method_config_table* table1, - grpc_method_config_table* table2) { +int grpc_method_config_table_cmp(const grpc_method_config_table* table1, + const grpc_method_config_table* table2) { return grpc_hash_table_cmp(table1, table2); } grpc_method_config* grpc_method_config_table_get_method_config( - grpc_method_config_table* table, grpc_mdstr* path) { + const grpc_method_config_table* table, const grpc_mdstr* path) { grpc_method_config* method_config = grpc_hash_table_get(table, path); // If we didn't find a match for the path, try looking for a wildcard // entry (i.e., change "/service/method" to "/service/*"). diff --git a/src/core/ext/client_config/method_config.h b/src/core/ext/client_config/method_config.h index 65b34a768a9..04e6bc81415 100644 --- a/src/core/ext/client_config/method_config.h +++ b/src/core/ext/client_config/method_config.h @@ -51,17 +51,19 @@ grpc_method_config* grpc_method_config_create( grpc_method_config* grpc_method_config_ref(grpc_method_config* method_config); void grpc_method_config_unref(grpc_method_config* method_config); -int grpc_method_config_cmp(grpc_method_config* method_config1, - grpc_method_config* method_config2); +int grpc_method_config_cmp(const grpc_method_config* method_config1, + const grpc_method_config* method_config2); /// These methods return NULL if the requested field is unset. /// The caller does NOT take ownership of the result. -bool* grpc_method_config_get_wait_for_ready(grpc_method_config* method_config); -gpr_timespec* grpc_method_config_get_timeout(grpc_method_config* method_config); -int32_t* grpc_method_config_get_max_request_message_bytes( - grpc_method_config* method_config); -int32_t* grpc_method_config_get_max_response_message_bytes( - grpc_method_config* method_config); +const bool* grpc_method_config_get_wait_for_ready( + const grpc_method_config* method_config); +const gpr_timespec* grpc_method_config_get_timeout( + const grpc_method_config* method_config); +const int32_t* grpc_method_config_get_max_request_message_bytes( + const grpc_method_config* method_config); +const int32_t* grpc_method_config_get_max_response_message_bytes( + const grpc_method_config* method_config); /// A table of method configs. typedef grpc_hash_table grpc_method_config_table; @@ -82,13 +84,13 @@ grpc_method_config_table* grpc_method_config_table_ref( grpc_method_config_table* table); void grpc_method_config_table_unref(grpc_method_config_table* table); -int grpc_method_config_table_cmp(grpc_method_config_table* table1, - grpc_method_config_table* table2); +int grpc_method_config_table_cmp(const grpc_method_config_table* table1, + const grpc_method_config_table* table2); /// Returns NULL if the method has no config. /// Caller does NOT own a reference to the result. grpc_method_config* grpc_method_config_table_get_method_config( - grpc_method_config_table* table, grpc_mdstr* path); + const grpc_method_config_table* table, const grpc_mdstr* path); /// Returns a channel arg containing \a table. grpc_arg grpc_method_config_table_create_channel_arg( diff --git a/src/core/lib/channel/message_size_filter.c b/src/core/lib/channel/message_size_filter.c index dbd8afd465b..1382f199453 100644 --- a/src/core/lib/channel/message_size_filter.c +++ b/src/core/lib/channel/message_size_filter.c @@ -137,14 +137,14 @@ static grpc_error* init_call_elem(grpc_exec_ctx* exec_ctx, grpc_method_config_table_get_method_config(chand->method_config_table, args->path); if (method_config != NULL) { - int32_t* max_request_message_bytes = + const int32_t* max_request_message_bytes = grpc_method_config_get_max_request_message_bytes(method_config); if (max_request_message_bytes != NULL && (*max_request_message_bytes < calld->max_send_size || calld->max_send_size < 0)) { calld->max_send_size = *max_request_message_bytes; } - int32_t* max_response_message_bytes = + const int32_t* max_response_message_bytes = grpc_method_config_get_max_response_message_bytes(method_config); if (max_response_message_bytes != NULL && (*max_response_message_bytes < calld->max_recv_size || diff --git a/src/core/lib/transport/hashtable.c b/src/core/lib/transport/hashtable.c index 838fe1026e3..d127f17a378 100644 --- a/src/core/lib/transport/hashtable.c +++ b/src/core/lib/transport/hashtable.c @@ -47,8 +47,8 @@ struct grpc_hash_table { // Helper function for insert and get operations that performs quadratic // probing (https://en.wikipedia.org/wiki/Quadratic_probing). -static size_t grpc_hash_table_find_index(grpc_hash_table* table, - grpc_mdstr* key, bool find_empty) { +static size_t grpc_hash_table_find_index( + const grpc_hash_table* table, const grpc_mdstr* key, bool find_empty) { for (size_t i = 0; i < table->num_entries; ++i) { const size_t idx = (key->hash + i * i) % table->num_entries; if (table->entries[idx].key == NULL) @@ -111,14 +111,15 @@ int grpc_hash_table_unref(grpc_hash_table* table) { return 0; } -void* grpc_hash_table_get(grpc_hash_table* table, grpc_mdstr* key) { +void* grpc_hash_table_get(const grpc_hash_table* table, const grpc_mdstr* key) { const size_t idx = grpc_hash_table_find_index(table, key, false /* find_empty */); if (idx == table->num_entries) return NULL; // Not found. return table->entries[idx].value; } -int grpc_hash_table_cmp(grpc_hash_table* table1, grpc_hash_table* table2) { +int grpc_hash_table_cmp(const grpc_hash_table* table1, + const grpc_hash_table* table2) { // Compare by num_entries. if (table1->num_entries < table2->num_entries) return -1; if (table1->num_entries > table2->num_entries) return 1; diff --git a/src/core/lib/transport/hashtable.h b/src/core/lib/transport/hashtable.h index 3ec48dce3a7..0ce51383c7d 100644 --- a/src/core/lib/transport/hashtable.h +++ b/src/core/lib/transport/hashtable.h @@ -74,9 +74,10 @@ int grpc_hash_table_unref(grpc_hash_table* table); /** Returns the value from \a table associated with \a key. Returns NULL if \a key is not found. */ -void* grpc_hash_table_get(grpc_hash_table* table, grpc_mdstr* key); +void* grpc_hash_table_get(const grpc_hash_table* table, const grpc_mdstr* key); /** Compares two hash tables. */ -int grpc_hash_table_cmp(grpc_hash_table* table1, grpc_hash_table* table2); +int grpc_hash_table_cmp(const grpc_hash_table* table1, + const grpc_hash_table* table2); #endif /* GRPC_CORE_LIB_TRANSPORT_HASHTABLE_H */ From 7347ad8fe07b7a288572dd5543019440112f61b1 Mon Sep 17 00:00:00 2001 From: Ken Payson Date: Tue, 11 Oct 2016 11:12:29 -0700 Subject: [PATCH 31/48] Use booleans instead of bitmask args --- src/core/lib/iomgr/ev_poll_posix.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/core/lib/iomgr/ev_poll_posix.c b/src/core/lib/iomgr/ev_poll_posix.c index 3de329c645d..1fead8a895c 100644 --- a/src/core/lib/iomgr/ev_poll_posix.c +++ b/src/core/lib/iomgr/ev_poll_posix.c @@ -968,8 +968,7 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, } else { // Wake up all the file descriptors, if we have an invalid one // we can identify it on the next pollset_work() - fd_end_poll(exec_ctx, &watchers[i], POLLIN_CHECK, POLLOUT_CHECK, - pollset); + fd_end_poll(exec_ctx, &watchers[i], 1, 1, pollset); } } } else if (r == 0) { From 070a2873c5b19a86a3054c295cba4c20a8640d5d Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Wed, 12 Oct 2016 08:09:30 -0700 Subject: [PATCH 32/48] Improve documentation in method_config.h. --- src/core/ext/client_config/method_config.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/core/ext/client_config/method_config.h b/src/core/ext/client_config/method_config.h index 04e6bc81415..d228b979488 100644 --- a/src/core/ext/client_config/method_config.h +++ b/src/core/ext/client_config/method_config.h @@ -43,7 +43,18 @@ /// Per-method configuration. typedef struct grpc_method_config grpc_method_config; +/// Creates a grpc_method_config with the specified parameters. /// Any parameter may be NULL to indicate that the value is unset. +/// +/// \a wait_for_ready indicates whether the client should wait until the +/// request deadline for the channel to become ready, even if there is a +/// temporary failure before the deadline while attempting to connect. +/// +/// \a timeout indicates the timeout for calls. +/// +/// \a max_request_message_bytes and \a max_response_message_bytes +/// indicate the maximum sizes of the request (checked when sending) and +/// response (checked when receiving) messages. grpc_method_config* grpc_method_config_create( bool* wait_for_ready, gpr_timespec* timeout, int32_t* max_request_message_bytes, int32_t* max_response_message_bytes); @@ -51,6 +62,8 @@ grpc_method_config* grpc_method_config_create( grpc_method_config* grpc_method_config_ref(grpc_method_config* method_config); void grpc_method_config_unref(grpc_method_config* method_config); +/// Compares two grpc_method_configs. +/// The sort order is stable but undefined. int grpc_method_config_cmp(const grpc_method_config* method_config1, const grpc_method_config* method_config2); @@ -84,9 +97,13 @@ grpc_method_config_table* grpc_method_config_table_ref( grpc_method_config_table* table); void grpc_method_config_table_unref(grpc_method_config_table* table); +/// Compares two grpc_method_config_tables. +/// The sort order is stable but undefined. int grpc_method_config_table_cmp(const grpc_method_config_table* table1, const grpc_method_config_table* table2); +/// Gets the method config for the specified \a path, which should be of +/// the form "/service/method". /// Returns NULL if the method has no config. /// Caller does NOT own a reference to the result. grpc_method_config* grpc_method_config_table_get_method_config( From 624997a24da31a7f4955701b37b9612a440b1296 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Wed, 12 Oct 2016 11:35:09 -0700 Subject: [PATCH 33/48] Code review changes. --- src/core/lib/transport/hashtable.c | 3 +-- src/core/lib/transport/hashtable.h | 7 +++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/core/lib/transport/hashtable.c b/src/core/lib/transport/hashtable.c index d127f17a378..a1bae147cce 100644 --- a/src/core/lib/transport/hashtable.c +++ b/src/core/lib/transport/hashtable.c @@ -64,8 +64,7 @@ static void grpc_hash_table_add(grpc_hash_table* table, grpc_mdstr* key, GPR_ASSERT(value != NULL); const size_t idx = grpc_hash_table_find_index(table, key, true /* find_empty */); - // This can happen if the table is full. - GPR_ASSERT(idx != table->num_entries); + GPR_ASSERT(idx != table->num_entries); // Table should never be full. grpc_hash_table_entry* entry = &table->entries[idx]; entry->key = GRPC_MDSTR_REF(key); entry->value = vtable->copy_value(value); diff --git a/src/core/lib/transport/hashtable.h b/src/core/lib/transport/hashtable.h index 0ce51383c7d..d5f40a2cf7b 100644 --- a/src/core/lib/transport/hashtable.h +++ b/src/core/lib/transport/hashtable.h @@ -39,10 +39,8 @@ * This implementation uses open addressing * (https://en.wikipedia.org/wiki/Open_addressing) with quadratic * probing (https://en.wikipedia.org/wiki/Quadratic_probing). - * This means that the hash table is of fixed size and cannot contain - * more than that number of elements. * - * The keys are grpc_mdstr objects. The values are arbitrary pointers + * The keys are \a grpc_mdstr objects. The values are arbitrary pointers * with a common vtable. * * Hash tables are intentionally immutable, to avoid the need for locking. @@ -76,7 +74,8 @@ int grpc_hash_table_unref(grpc_hash_table* table); Returns NULL if \a key is not found. */ void* grpc_hash_table_get(const grpc_hash_table* table, const grpc_mdstr* key); -/** Compares two hash tables. */ +/** Compares two hash tables. + The sort order is stable but undefined. */ int grpc_hash_table_cmp(const grpc_hash_table* table1, const grpc_hash_table* table2); From 31292f211feecb14a8e2e57c08bd3995c00a2c87 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Wed, 12 Oct 2016 13:14:07 -0700 Subject: [PATCH 34/48] Hold a ref to the call stack for the read_service_config callback. --- src/core/ext/client_config/client_channel.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/core/ext/client_config/client_channel.c b/src/core/ext/client_config/client_channel.c index 0594c0b3aca..ac0f271d069 100644 --- a/src/core/ext/client_config/client_channel.c +++ b/src/core/ext/client_config/client_channel.c @@ -869,6 +869,7 @@ static void read_service_config(grpc_exec_ctx *exec_ctx, void *arg, } grpc_method_config_table_unref(method_config_table); } + GRPC_CALL_STACK_UNREF(exec_ctx, calld->owning_call, "read_service_config"); } /* Constructor for call_data */ @@ -933,6 +934,8 @@ static grpc_error *cc_init_call_elem(grpc_exec_ctx *exec_ctx, } else { // We don't yet have a resolver result, so register a callback to // get the service config data once the resolver returns. + // Take a reference to the call stack to be owned by the callback. + GRPC_CALL_STACK_REF(calld->owning_call, "read_service_config"); grpc_closure_init(&calld->read_service_config, read_service_config, elem); grpc_closure_list_append(&chand->waiting_for_config_closures, &calld->read_service_config, GRPC_ERROR_NONE); From 196387a934c7757ab2e60e03dd764b31fd6879ea Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Wed, 12 Oct 2016 14:53:36 -0700 Subject: [PATCH 35/48] Unref the call stack in read_service_config even on error. --- src/core/ext/client_config/client_channel.c | 69 +++++++++++---------- 1 file changed, 35 insertions(+), 34 deletions(-) diff --git a/src/core/ext/client_config/client_channel.c b/src/core/ext/client_config/client_channel.c index ac0f271d069..de0d42f4743 100644 --- a/src/core/ext/client_config/client_channel.c +++ b/src/core/ext/client_config/client_channel.c @@ -830,44 +830,45 @@ static void read_service_config(grpc_exec_ctx *exec_ctx, void *arg, channel_data *chand = elem->channel_data; call_data *calld = elem->call_data; // If this is an error, there's no point in looking at the service config. - if (error != GRPC_ERROR_NONE) return; - // Get the method config table from channel data. - gpr_mu_lock(&chand->mu); - grpc_method_config_table *method_config_table = NULL; - if (chand->method_config_table != NULL) { - method_config_table = - grpc_method_config_table_ref(chand->method_config_table); - } - gpr_mu_unlock(&chand->mu); - // If the method config table was present, use it. - if (method_config_table != NULL) { - const grpc_method_config *method_config = - grpc_method_config_table_get_method_config(method_config_table, - calld->path); - if (method_config != NULL) { - const gpr_timespec *per_method_timeout = - grpc_method_config_get_timeout(method_config); - const bool *wait_for_ready = - grpc_method_config_get_wait_for_ready(method_config); - if (per_method_timeout != NULL || wait_for_ready != NULL) { - gpr_mu_lock(&calld->mu); - if (per_method_timeout != NULL) { - gpr_timespec per_method_deadline = - gpr_time_add(calld->call_start_time, *per_method_timeout); - if (gpr_time_cmp(per_method_deadline, calld->deadline) < 0) { - calld->deadline = per_method_deadline; - // Reset deadline timer. - grpc_deadline_state_reset(exec_ctx, elem, calld->deadline); + if (error == GRPC_ERROR_NONE) { + // Get the method config table from channel data. + gpr_mu_lock(&chand->mu); + grpc_method_config_table *method_config_table = NULL; + if (chand->method_config_table != NULL) { + method_config_table = + grpc_method_config_table_ref(chand->method_config_table); + } + gpr_mu_unlock(&chand->mu); + // If the method config table was present, use it. + if (method_config_table != NULL) { + const grpc_method_config *method_config = + grpc_method_config_table_get_method_config(method_config_table, + calld->path); + if (method_config != NULL) { + const gpr_timespec *per_method_timeout = + grpc_method_config_get_timeout(method_config); + const bool *wait_for_ready = + grpc_method_config_get_wait_for_ready(method_config); + if (per_method_timeout != NULL || wait_for_ready != NULL) { + gpr_mu_lock(&calld->mu); + if (per_method_timeout != NULL) { + gpr_timespec per_method_deadline = + gpr_time_add(calld->call_start_time, *per_method_timeout); + if (gpr_time_cmp(per_method_deadline, calld->deadline) < 0) { + calld->deadline = per_method_deadline; + // Reset deadline timer. + grpc_deadline_state_reset(exec_ctx, elem, calld->deadline); + } } + if (wait_for_ready != NULL) { + calld->wait_for_ready_from_service_config = + *wait_for_ready ? WAIT_FOR_READY_TRUE : WAIT_FOR_READY_FALSE; + } + gpr_mu_unlock(&calld->mu); } - if (wait_for_ready != NULL) { - calld->wait_for_ready_from_service_config = - *wait_for_ready ? WAIT_FOR_READY_TRUE : WAIT_FOR_READY_FALSE; - } - gpr_mu_unlock(&calld->mu); } + grpc_method_config_table_unref(method_config_table); } - grpc_method_config_table_unref(method_config_table); } GRPC_CALL_STACK_UNREF(exec_ctx, calld->owning_call, "read_service_config"); } From 55f25b6c27b42b81ccb9bd9c7adf9a87cadd6da0 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Wed, 12 Oct 2016 14:55:20 -0700 Subject: [PATCH 36/48] clang-format --- src/core/ext/client_config/client_channel.c | 5 ++--- src/core/lib/transport/hashtable.c | 5 +++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/core/ext/client_config/client_channel.c b/src/core/ext/client_config/client_channel.c index de0d42f4743..fb3e17a7d9f 100644 --- a/src/core/ext/client_config/client_channel.c +++ b/src/core/ext/client_config/client_channel.c @@ -680,9 +680,8 @@ static bool pick_subchannel(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, const grpc_lb_policy_pick_args inputs = { calld->pollent, initial_metadata, initial_metadata_flags, &calld->lb_token_mdelem, gpr_inf_future(GPR_CLOCK_MONOTONIC)}; - const bool result = - grpc_lb_policy_pick(exec_ctx, lb_policy, &inputs, - connected_subchannel, NULL, on_ready); + const bool result = grpc_lb_policy_pick( + exec_ctx, lb_policy, &inputs, connected_subchannel, NULL, on_ready); GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "pick_subchannel"); GPR_TIMER_END("pick_subchannel", 0); return result; diff --git a/src/core/lib/transport/hashtable.c b/src/core/lib/transport/hashtable.c index a1bae147cce..a016daa0ecc 100644 --- a/src/core/lib/transport/hashtable.c +++ b/src/core/lib/transport/hashtable.c @@ -47,8 +47,9 @@ struct grpc_hash_table { // Helper function for insert and get operations that performs quadratic // probing (https://en.wikipedia.org/wiki/Quadratic_probing). -static size_t grpc_hash_table_find_index( - const grpc_hash_table* table, const grpc_mdstr* key, bool find_empty) { +static size_t grpc_hash_table_find_index(const grpc_hash_table* table, + const grpc_mdstr* key, + bool find_empty) { for (size_t i = 0; i < table->num_entries; ++i) { const size_t idx = (key->hash + i * i) % table->num_entries; if (table->entries[idx].key == NULL) From f635fb90cad8f5dc534afda09fb4eb19f06a6e4a Mon Sep 17 00:00:00 2001 From: Yuxuan Li Date: Thu, 13 Oct 2016 14:56:20 -0700 Subject: [PATCH 37/48] change from malloc to gpr_malloc --- src/core/lib/channel/handshaker.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/lib/channel/handshaker.c b/src/core/lib/channel/handshaker.c index 8f9fb17a31c..0d759887bc1 100644 --- a/src/core/lib/channel/handshaker.c +++ b/src/core/lib/channel/handshaker.c @@ -183,7 +183,7 @@ void grpc_handshake_manager_do_handshake( gpr_timespec deadline, grpc_tcp_server_acceptor* acceptor, grpc_handshaker_done_cb cb, void* user_data) { grpc_channel_args* args_copy = grpc_channel_args_copy(args); - gpr_slice_buffer* read_buffer = malloc(sizeof(*read_buffer)); + gpr_slice_buffer* read_buffer = gpr_malloc(sizeof(*read_buffer)); gpr_slice_buffer_init(read_buffer); if (mgr->count == 0) { // No handshakers registered, so we just immediately call the done From 6a721b5b3f253b86eac3f34c66e6b2d47bb08c9e Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Fri, 14 Oct 2016 12:43:34 -0700 Subject: [PATCH 38/48] Rename grpc_hash_table to grpc_mdstr_hash_table. --- BUILD | 16 ++--- CMakeLists.txt | 6 +- Makefile | 8 +-- binding.gyp | 2 +- build.yaml | 4 +- config.m4 | 2 +- gRPC-Core.podspec | 6 +- grpc.gemspec | 4 +- package.xml | 4 +- src/core/ext/client_config/method_config.c | 58 ++++++++++--------- src/core/ext/client_config/method_config.h | 4 +- .../{hashtable.c => mdstr_hash_table.c} | 54 ++++++++--------- .../{hashtable.h => mdstr_hash_table.h} | 33 ++++++----- src/python/grpcio/grpc_core_dependencies.py | 2 +- tools/doxygen/Doxyfile.core.internal | 4 +- tools/run_tests/sources_and_headers.json | 6 +- vsprojects/vcxproj/grpc/grpc.vcxproj | 4 +- vsprojects/vcxproj/grpc/grpc.vcxproj.filters | 4 +- .../grpc_test_util/grpc_test_util.vcxproj | 4 +- .../grpc_test_util.vcxproj.filters | 4 +- .../grpc_unsecure/grpc_unsecure.vcxproj | 4 +- .../grpc_unsecure.vcxproj.filters | 4 +- 22 files changed, 122 insertions(+), 115 deletions(-) rename src/core/lib/transport/{hashtable.c => mdstr_hash_table.c} (70%) rename src/core/lib/transport/{hashtable.h => mdstr_hash_table.h} (73%) diff --git a/BUILD b/BUILD index a1be967ee40..4128ea6bf63 100644 --- a/BUILD +++ b/BUILD @@ -239,7 +239,7 @@ cc_library( "src/core/lib/surface/server.h", "src/core/lib/transport/byte_stream.h", "src/core/lib/transport/connectivity_state.h", - "src/core/lib/transport/hashtable.h", + "src/core/lib/transport/mdstr_hash_table.h", "src/core/lib/transport/metadata.h", "src/core/lib/transport/metadata_batch.h", "src/core/lib/transport/static_metadata.h", @@ -411,7 +411,7 @@ cc_library( "src/core/lib/surface/version.c", "src/core/lib/transport/byte_stream.c", "src/core/lib/transport/connectivity_state.c", - "src/core/lib/transport/hashtable.c", + "src/core/lib/transport/mdstr_hash_table.c", "src/core/lib/transport/metadata.c", "src/core/lib/transport/metadata_batch.c", "src/core/lib/transport/static_metadata.c", @@ -644,7 +644,7 @@ cc_library( "src/core/lib/surface/server.h", "src/core/lib/transport/byte_stream.h", "src/core/lib/transport/connectivity_state.h", - "src/core/lib/transport/hashtable.h", + "src/core/lib/transport/mdstr_hash_table.h", "src/core/lib/transport/metadata.h", "src/core/lib/transport/metadata_batch.h", "src/core/lib/transport/static_metadata.h", @@ -801,7 +801,7 @@ cc_library( "src/core/lib/surface/version.c", "src/core/lib/transport/byte_stream.c", "src/core/lib/transport/connectivity_state.c", - "src/core/lib/transport/hashtable.c", + "src/core/lib/transport/mdstr_hash_table.c", "src/core/lib/transport/metadata.c", "src/core/lib/transport/metadata_batch.c", "src/core/lib/transport/static_metadata.c", @@ -1004,7 +1004,7 @@ cc_library( "src/core/lib/surface/server.h", "src/core/lib/transport/byte_stream.h", "src/core/lib/transport/connectivity_state.h", - "src/core/lib/transport/hashtable.h", + "src/core/lib/transport/mdstr_hash_table.h", "src/core/lib/transport/metadata.h", "src/core/lib/transport/metadata_batch.h", "src/core/lib/transport/static_metadata.h", @@ -1153,7 +1153,7 @@ cc_library( "src/core/lib/surface/version.c", "src/core/lib/transport/byte_stream.c", "src/core/lib/transport/connectivity_state.c", - "src/core/lib/transport/hashtable.c", + "src/core/lib/transport/mdstr_hash_table.c", "src/core/lib/transport/metadata.c", "src/core/lib/transport/metadata_batch.c", "src/core/lib/transport/static_metadata.c", @@ -1918,7 +1918,7 @@ objc_library( "src/core/lib/surface/version.c", "src/core/lib/transport/byte_stream.c", "src/core/lib/transport/connectivity_state.c", - "src/core/lib/transport/hashtable.c", + "src/core/lib/transport/mdstr_hash_table.c", "src/core/lib/transport/metadata.c", "src/core/lib/transport/metadata_batch.c", "src/core/lib/transport/static_metadata.c", @@ -2130,7 +2130,7 @@ objc_library( "src/core/lib/surface/server.h", "src/core/lib/transport/byte_stream.h", "src/core/lib/transport/connectivity_state.h", - "src/core/lib/transport/hashtable.h", + "src/core/lib/transport/mdstr_hash_table.h", "src/core/lib/transport/metadata.h", "src/core/lib/transport/metadata_batch.h", "src/core/lib/transport/static_metadata.h", diff --git a/CMakeLists.txt b/CMakeLists.txt index 21c38baba30..366480eb005 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -376,7 +376,7 @@ add_library(grpc src/core/lib/surface/version.c src/core/lib/transport/byte_stream.c src/core/lib/transport/connectivity_state.c - src/core/lib/transport/hashtable.c + src/core/lib/transport/mdstr_hash_table.c src/core/lib/transport/metadata.c src/core/lib/transport/metadata_batch.c src/core/lib/transport/static_metadata.c @@ -637,7 +637,7 @@ add_library(grpc_cronet src/core/lib/surface/version.c src/core/lib/transport/byte_stream.c src/core/lib/transport/connectivity_state.c - src/core/lib/transport/hashtable.c + src/core/lib/transport/mdstr_hash_table.c src/core/lib/transport/metadata.c src/core/lib/transport/metadata_batch.c src/core/lib/transport/static_metadata.c @@ -870,7 +870,7 @@ add_library(grpc_unsecure src/core/lib/surface/version.c src/core/lib/transport/byte_stream.c src/core/lib/transport/connectivity_state.c - src/core/lib/transport/hashtable.c + src/core/lib/transport/mdstr_hash_table.c src/core/lib/transport/metadata.c src/core/lib/transport/metadata_batch.c src/core/lib/transport/static_metadata.c diff --git a/Makefile b/Makefile index 44738bd20c0..4892ae98fb3 100644 --- a/Makefile +++ b/Makefile @@ -2624,7 +2624,7 @@ LIBGRPC_SRC = \ src/core/lib/surface/version.c \ src/core/lib/transport/byte_stream.c \ src/core/lib/transport/connectivity_state.c \ - src/core/lib/transport/hashtable.c \ + src/core/lib/transport/mdstr_hash_table.c \ src/core/lib/transport/metadata.c \ src/core/lib/transport/metadata_batch.c \ src/core/lib/transport/static_metadata.c \ @@ -2903,7 +2903,7 @@ LIBGRPC_CRONET_SRC = \ src/core/lib/surface/version.c \ src/core/lib/transport/byte_stream.c \ src/core/lib/transport/connectivity_state.c \ - src/core/lib/transport/hashtable.c \ + src/core/lib/transport/mdstr_hash_table.c \ src/core/lib/transport/metadata.c \ src/core/lib/transport/metadata_batch.c \ src/core/lib/transport/static_metadata.c \ @@ -3172,7 +3172,7 @@ LIBGRPC_TEST_UTIL_SRC = \ src/core/lib/surface/version.c \ src/core/lib/transport/byte_stream.c \ src/core/lib/transport/connectivity_state.c \ - src/core/lib/transport/hashtable.c \ + src/core/lib/transport/mdstr_hash_table.c \ src/core/lib/transport/metadata.c \ src/core/lib/transport/metadata_batch.c \ src/core/lib/transport/static_metadata.c \ @@ -3367,7 +3367,7 @@ LIBGRPC_UNSECURE_SRC = \ src/core/lib/surface/version.c \ src/core/lib/transport/byte_stream.c \ src/core/lib/transport/connectivity_state.c \ - src/core/lib/transport/hashtable.c \ + src/core/lib/transport/mdstr_hash_table.c \ src/core/lib/transport/metadata.c \ src/core/lib/transport/metadata_batch.c \ src/core/lib/transport/static_metadata.c \ diff --git a/binding.gyp b/binding.gyp index 88acd1786b8..60e2278cd99 100644 --- a/binding.gyp +++ b/binding.gyp @@ -651,7 +651,7 @@ 'src/core/lib/surface/version.c', 'src/core/lib/transport/byte_stream.c', 'src/core/lib/transport/connectivity_state.c', - 'src/core/lib/transport/hashtable.c', + 'src/core/lib/transport/mdstr_hash_table.c', 'src/core/lib/transport/metadata.c', 'src/core/lib/transport/metadata_batch.c', 'src/core/lib/transport/static_metadata.c', diff --git a/build.yaml b/build.yaml index 9cec3aeab4d..c167ebf990e 100644 --- a/build.yaml +++ b/build.yaml @@ -243,7 +243,7 @@ filegroups: - src/core/lib/surface/server.h - src/core/lib/transport/byte_stream.h - src/core/lib/transport/connectivity_state.h - - src/core/lib/transport/hashtable.h + - src/core/lib/transport/mdstr_hash_table.h - src/core/lib/transport/metadata.h - src/core/lib/transport/metadata_batch.h - src/core/lib/transport/static_metadata.h @@ -337,7 +337,7 @@ filegroups: - src/core/lib/surface/version.c - src/core/lib/transport/byte_stream.c - src/core/lib/transport/connectivity_state.c - - src/core/lib/transport/hashtable.c + - src/core/lib/transport/mdstr_hash_table.c - src/core/lib/transport/metadata.c - src/core/lib/transport/metadata_batch.c - src/core/lib/transport/static_metadata.c diff --git a/config.m4 b/config.m4 index f65f617f9ad..c3f2e20c203 100644 --- a/config.m4 +++ b/config.m4 @@ -170,7 +170,7 @@ if test "$PHP_GRPC" != "no"; then src/core/lib/surface/version.c \ src/core/lib/transport/byte_stream.c \ src/core/lib/transport/connectivity_state.c \ - src/core/lib/transport/hashtable.c \ + src/core/lib/transport/mdstr_hash_table.c \ src/core/lib/transport/metadata.c \ src/core/lib/transport/metadata_batch.c \ src/core/lib/transport/static_metadata.c \ diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec index ffa7ca08258..0712e6de9ff 100644 --- a/gRPC-Core.podspec +++ b/gRPC-Core.podspec @@ -326,7 +326,7 @@ Pod::Spec.new do |s| 'src/core/lib/surface/server.h', 'src/core/lib/transport/byte_stream.h', 'src/core/lib/transport/connectivity_state.h', - 'src/core/lib/transport/hashtable.h', + 'src/core/lib/transport/mdstr_hash_table.h', 'src/core/lib/transport/metadata.h', 'src/core/lib/transport/metadata_batch.h', 'src/core/lib/transport/static_metadata.h', @@ -502,7 +502,7 @@ Pod::Spec.new do |s| 'src/core/lib/surface/version.c', 'src/core/lib/transport/byte_stream.c', 'src/core/lib/transport/connectivity_state.c', - 'src/core/lib/transport/hashtable.c', + 'src/core/lib/transport/mdstr_hash_table.c', 'src/core/lib/transport/metadata.c', 'src/core/lib/transport/metadata_batch.c', 'src/core/lib/transport/static_metadata.c', @@ -703,7 +703,7 @@ Pod::Spec.new do |s| 'src/core/lib/surface/server.h', 'src/core/lib/transport/byte_stream.h', 'src/core/lib/transport/connectivity_state.h', - 'src/core/lib/transport/hashtable.h', + 'src/core/lib/transport/mdstr_hash_table.h', 'src/core/lib/transport/metadata.h', 'src/core/lib/transport/metadata_batch.h', 'src/core/lib/transport/static_metadata.h', diff --git a/grpc.gemspec b/grpc.gemspec index e547811332d..e3834f2127f 100755 --- a/grpc.gemspec +++ b/grpc.gemspec @@ -246,7 +246,7 @@ Gem::Specification.new do |s| s.files += %w( src/core/lib/surface/server.h ) s.files += %w( src/core/lib/transport/byte_stream.h ) s.files += %w( src/core/lib/transport/connectivity_state.h ) - s.files += %w( src/core/lib/transport/hashtable.h ) + s.files += %w( src/core/lib/transport/mdstr_hash_table.h ) s.files += %w( src/core/lib/transport/metadata.h ) s.files += %w( src/core/lib/transport/metadata_batch.h ) s.files += %w( src/core/lib/transport/static_metadata.h ) @@ -422,7 +422,7 @@ Gem::Specification.new do |s| s.files += %w( src/core/lib/surface/version.c ) s.files += %w( src/core/lib/transport/byte_stream.c ) s.files += %w( src/core/lib/transport/connectivity_state.c ) - s.files += %w( src/core/lib/transport/hashtable.c ) + s.files += %w( src/core/lib/transport/mdstr_hash_table.c ) s.files += %w( src/core/lib/transport/metadata.c ) s.files += %w( src/core/lib/transport/metadata_batch.c ) s.files += %w( src/core/lib/transport/static_metadata.c ) diff --git a/package.xml b/package.xml index bf452c3b162..49b71eef0f2 100644 --- a/package.xml +++ b/package.xml @@ -253,7 +253,7 @@ - + @@ -429,7 +429,7 @@ - + diff --git a/src/core/ext/client_config/method_config.c b/src/core/ext/client_config/method_config.c index 3699c22810a..f8a82323e70 100644 --- a/src/core/ext/client_config/method_config.c +++ b/src/core/ext/client_config/method_config.c @@ -39,7 +39,7 @@ #include #include -#include "src/core/lib/transport/hashtable.h" +#include "src/core/lib/transport/mdstr_hash_table.h" #include "src/core/lib/transport/metadata.h" // @@ -63,7 +63,8 @@ static int bool_cmp(void* v1, void* v2) { return 0; } -static grpc_hash_table_vtable bool_vtable = {gpr_free, bool_copy, bool_cmp}; +static grpc_mdstr_hash_table_vtable bool_vtable = {gpr_free, bool_copy, + bool_cmp}; // timespec vtable @@ -78,8 +79,8 @@ static int timespec_cmp(void* v1, void* v2) { return gpr_time_cmp(*(gpr_timespec*)v1, *(gpr_timespec*)v2); } -static grpc_hash_table_vtable timespec_vtable = {gpr_free, timespec_copy, - timespec_cmp}; +static grpc_mdstr_hash_table_vtable timespec_vtable = {gpr_free, timespec_copy, + timespec_cmp}; // int32 vtable @@ -98,7 +99,8 @@ static int int32_cmp(void* v1, void* v2) { return 0; } -static grpc_hash_table_vtable int32_vtable = {gpr_free, int32_copy, int32_cmp}; +static grpc_mdstr_hash_table_vtable int32_vtable = {gpr_free, int32_copy, + int32_cmp}; // Hash table keys. #define GRPC_METHOD_CONFIG_WAIT_FOR_READY "grpc.wait_for_ready" // bool @@ -109,7 +111,7 @@ static grpc_hash_table_vtable int32_vtable = {gpr_free, int32_copy, int32_cmp}; "grpc.max_response_message_bytes" // int32 struct grpc_method_config { - grpc_hash_table* table; + grpc_mdstr_hash_table* table; grpc_mdstr* wait_for_ready_key; grpc_mdstr* timeout_key; grpc_mdstr* max_request_message_bytes_key; @@ -129,7 +131,7 @@ grpc_method_config* grpc_method_config_create( grpc_mdstr_from_string(GRPC_METHOD_CONFIG_MAX_REQUEST_MESSAGE_BYTES); method_config->max_response_message_bytes_key = grpc_mdstr_from_string(GRPC_METHOD_CONFIG_MAX_RESPONSE_MESSAGE_BYTES); - grpc_hash_table_entry entries[4]; + grpc_mdstr_hash_table_entry entries[4]; size_t num_entries = 0; if (wait_for_ready != NULL) { entries[num_entries].key = method_config->wait_for_ready_key; @@ -155,17 +157,17 @@ grpc_method_config* grpc_method_config_create( entries[num_entries].vtable = &int32_vtable; ++num_entries; } - method_config->table = grpc_hash_table_create(num_entries, entries); + method_config->table = grpc_mdstr_hash_table_create(num_entries, entries); return method_config; } grpc_method_config* grpc_method_config_ref(grpc_method_config* method_config) { - grpc_hash_table_ref(method_config->table); + grpc_mdstr_hash_table_ref(method_config->table); return method_config; } void grpc_method_config_unref(grpc_method_config* method_config) { - if (grpc_hash_table_unref(method_config->table)) { + if (grpc_mdstr_hash_table_unref(method_config->table)) { GRPC_MDSTR_UNREF(method_config->wait_for_ready_key); GRPC_MDSTR_UNREF(method_config->timeout_key); GRPC_MDSTR_UNREF(method_config->max_request_message_bytes_key); @@ -176,30 +178,32 @@ void grpc_method_config_unref(grpc_method_config* method_config) { int grpc_method_config_cmp(const grpc_method_config* method_config1, const grpc_method_config* method_config2) { - return grpc_hash_table_cmp(method_config1->table, method_config2->table); + return grpc_mdstr_hash_table_cmp(method_config1->table, + method_config2->table); } const bool* grpc_method_config_get_wait_for_ready( const grpc_method_config* method_config) { - return grpc_hash_table_get(method_config->table, - method_config->wait_for_ready_key); + return grpc_mdstr_hash_table_get(method_config->table, + method_config->wait_for_ready_key); } const gpr_timespec* grpc_method_config_get_timeout( const grpc_method_config* method_config) { - return grpc_hash_table_get(method_config->table, method_config->timeout_key); + return grpc_mdstr_hash_table_get(method_config->table, + method_config->timeout_key); } const int32_t* grpc_method_config_get_max_request_message_bytes( const grpc_method_config* method_config) { - return grpc_hash_table_get(method_config->table, - method_config->max_request_message_bytes_key); + return grpc_mdstr_hash_table_get( + method_config->table, method_config->max_request_message_bytes_key); } const int32_t* grpc_method_config_get_max_response_message_bytes( const grpc_method_config* method_config) { - return grpc_hash_table_get(method_config->table, - method_config->max_response_message_bytes_key); + return grpc_mdstr_hash_table_get( + method_config->table, method_config->max_response_message_bytes_key); } // @@ -218,41 +222,41 @@ static int method_config_cmp(void* valuep1, void* valuep2) { return grpc_method_config_cmp(valuep1, valuep2); } -static const grpc_hash_table_vtable method_config_table_vtable = { +static const grpc_mdstr_hash_table_vtable method_config_table_vtable = { method_config_unref, method_config_ref, method_config_cmp}; grpc_method_config_table* grpc_method_config_table_create( size_t num_entries, grpc_method_config_table_entry* entries) { - grpc_hash_table_entry* hash_table_entries = - gpr_malloc(sizeof(grpc_hash_table_entry) * num_entries); + grpc_mdstr_hash_table_entry* hash_table_entries = + gpr_malloc(sizeof(grpc_mdstr_hash_table_entry) * num_entries); for (size_t i = 0; i < num_entries; ++i) { hash_table_entries[i].key = entries[i].method_name; hash_table_entries[i].value = entries[i].method_config; hash_table_entries[i].vtable = &method_config_table_vtable; } grpc_method_config_table* method_config_table = - grpc_hash_table_create(num_entries, hash_table_entries); + grpc_mdstr_hash_table_create(num_entries, hash_table_entries); gpr_free(hash_table_entries); return method_config_table; } grpc_method_config_table* grpc_method_config_table_ref( grpc_method_config_table* table) { - return grpc_hash_table_ref(table); + return grpc_mdstr_hash_table_ref(table); } void grpc_method_config_table_unref(grpc_method_config_table* table) { - grpc_hash_table_unref(table); + grpc_mdstr_hash_table_unref(table); } int grpc_method_config_table_cmp(const grpc_method_config_table* table1, const grpc_method_config_table* table2) { - return grpc_hash_table_cmp(table1, table2); + return grpc_mdstr_hash_table_cmp(table1, table2); } grpc_method_config* grpc_method_config_table_get_method_config( const grpc_method_config_table* table, const grpc_mdstr* path) { - grpc_method_config* method_config = grpc_hash_table_get(table, path); + grpc_method_config* method_config = grpc_mdstr_hash_table_get(table, path); // If we didn't find a match for the path, try looking for a wildcard // entry (i.e., change "/service/method" to "/service/*"). if (method_config == NULL) { @@ -265,7 +269,7 @@ grpc_method_config* grpc_method_config_table_get_method_config( buf[len + 1] = '\0'; grpc_mdstr* wildcard_path = grpc_mdstr_from_string(buf); gpr_free(buf); - method_config = grpc_hash_table_get(table, wildcard_path); + method_config = grpc_mdstr_hash_table_get(table, wildcard_path); GRPC_MDSTR_UNREF(wildcard_path); } return method_config; diff --git a/src/core/ext/client_config/method_config.h b/src/core/ext/client_config/method_config.h index d228b979488..1302ac425d5 100644 --- a/src/core/ext/client_config/method_config.h +++ b/src/core/ext/client_config/method_config.h @@ -37,7 +37,7 @@ #include #include -#include "src/core/lib/transport/hashtable.h" +#include "src/core/lib/transport/mdstr_hash_table.h" #include "src/core/lib/transport/metadata.h" /// Per-method configuration. @@ -79,7 +79,7 @@ const int32_t* grpc_method_config_get_max_response_message_bytes( const grpc_method_config* method_config); /// A table of method configs. -typedef grpc_hash_table grpc_method_config_table; +typedef grpc_mdstr_hash_table grpc_method_config_table; typedef struct grpc_method_config_table_entry { /// The name is of one of the following forms: diff --git a/src/core/lib/transport/hashtable.c b/src/core/lib/transport/mdstr_hash_table.c similarity index 70% rename from src/core/lib/transport/hashtable.c rename to src/core/lib/transport/mdstr_hash_table.c index a016daa0ecc..4be0536dd76 100644 --- a/src/core/lib/transport/hashtable.c +++ b/src/core/lib/transport/mdstr_hash_table.c @@ -29,7 +29,7 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -#include "src/core/lib/transport/hashtable.h" +#include "src/core/lib/transport/mdstr_hash_table.h" #include #include @@ -39,17 +39,17 @@ #include "src/core/lib/transport/metadata.h" -struct grpc_hash_table { +struct grpc_mdstr_hash_table { gpr_refcount refs; size_t num_entries; - grpc_hash_table_entry* entries; + grpc_mdstr_hash_table_entry* entries; }; // Helper function for insert and get operations that performs quadratic // probing (https://en.wikipedia.org/wiki/Quadratic_probing). -static size_t grpc_hash_table_find_index(const grpc_hash_table* table, - const grpc_mdstr* key, - bool find_empty) { +static size_t grpc_mdstr_hash_table_find_index( + const grpc_mdstr_hash_table* table, const grpc_mdstr* key, + bool find_empty) { for (size_t i = 0; i < table->num_entries; ++i) { const size_t idx = (key->hash + i * i) % table->num_entries; if (table->entries[idx].key == NULL) @@ -59,46 +59,47 @@ static size_t grpc_hash_table_find_index(const grpc_hash_table* table, return table->num_entries; // Not found. } -static void grpc_hash_table_add(grpc_hash_table* table, grpc_mdstr* key, - void* value, - const grpc_hash_table_vtable* vtable) { +static void grpc_mdstr_hash_table_add( + grpc_mdstr_hash_table* table, grpc_mdstr* key, void* value, + const grpc_mdstr_hash_table_vtable* vtable) { GPR_ASSERT(value != NULL); const size_t idx = - grpc_hash_table_find_index(table, key, true /* find_empty */); + grpc_mdstr_hash_table_find_index(table, key, true /* find_empty */); GPR_ASSERT(idx != table->num_entries); // Table should never be full. - grpc_hash_table_entry* entry = &table->entries[idx]; + grpc_mdstr_hash_table_entry* entry = &table->entries[idx]; entry->key = GRPC_MDSTR_REF(key); entry->value = vtable->copy_value(value); entry->vtable = vtable; } -grpc_hash_table* grpc_hash_table_create(size_t num_entries, - grpc_hash_table_entry* entries) { - grpc_hash_table* table = gpr_malloc(sizeof(*table)); +grpc_mdstr_hash_table* grpc_mdstr_hash_table_create( + size_t num_entries, grpc_mdstr_hash_table_entry* entries) { + grpc_mdstr_hash_table* table = gpr_malloc(sizeof(*table)); memset(table, 0, sizeof(*table)); gpr_ref_init(&table->refs, 1); // Quadratic probing gets best performance when the table is no more // than half full. table->num_entries = num_entries * 2; - const size_t entry_size = sizeof(grpc_hash_table_entry) * table->num_entries; + const size_t entry_size = + sizeof(grpc_mdstr_hash_table_entry) * table->num_entries; table->entries = gpr_malloc(entry_size); memset(table->entries, 0, entry_size); for (size_t i = 0; i < num_entries; ++i) { - grpc_hash_table_entry* entry = &entries[i]; - grpc_hash_table_add(table, entry->key, entry->value, entry->vtable); + grpc_mdstr_hash_table_entry* entry = &entries[i]; + grpc_mdstr_hash_table_add(table, entry->key, entry->value, entry->vtable); } return table; } -grpc_hash_table* grpc_hash_table_ref(grpc_hash_table* table) { +grpc_mdstr_hash_table* grpc_mdstr_hash_table_ref(grpc_mdstr_hash_table* table) { if (table != NULL) gpr_ref(&table->refs); return table; } -int grpc_hash_table_unref(grpc_hash_table* table) { +int grpc_mdstr_hash_table_unref(grpc_mdstr_hash_table* table) { if (table != NULL && gpr_unref(&table->refs)) { for (size_t i = 0; i < table->num_entries; ++i) { - grpc_hash_table_entry* entry = &table->entries[i]; + grpc_mdstr_hash_table_entry* entry = &table->entries[i]; if (entry->key != NULL) { GRPC_MDSTR_UNREF(entry->key); entry->vtable->destroy_value(entry->value); @@ -111,21 +112,22 @@ int grpc_hash_table_unref(grpc_hash_table* table) { return 0; } -void* grpc_hash_table_get(const grpc_hash_table* table, const grpc_mdstr* key) { +void* grpc_mdstr_hash_table_get(const grpc_mdstr_hash_table* table, + const grpc_mdstr* key) { const size_t idx = - grpc_hash_table_find_index(table, key, false /* find_empty */); + grpc_mdstr_hash_table_find_index(table, key, false /* find_empty */); if (idx == table->num_entries) return NULL; // Not found. return table->entries[idx].value; } -int grpc_hash_table_cmp(const grpc_hash_table* table1, - const grpc_hash_table* table2) { +int grpc_mdstr_hash_table_cmp(const grpc_mdstr_hash_table* table1, + const grpc_mdstr_hash_table* table2) { // Compare by num_entries. if (table1->num_entries < table2->num_entries) return -1; if (table1->num_entries > table2->num_entries) return 1; for (size_t i = 0; i < table1->num_entries; ++i) { - grpc_hash_table_entry* e1 = &table1->entries[i]; - grpc_hash_table_entry* e2 = &table2->entries[i]; + grpc_mdstr_hash_table_entry* e1 = &table1->entries[i]; + grpc_mdstr_hash_table_entry* e2 = &table2->entries[i]; // Compare keys by hash value. if (e1->key->hash < e2->key->hash) return -1; if (e1->key->hash > e2->key->hash) return 1; diff --git a/src/core/lib/transport/hashtable.h b/src/core/lib/transport/mdstr_hash_table.h similarity index 73% rename from src/core/lib/transport/hashtable.h rename to src/core/lib/transport/mdstr_hash_table.h index d5f40a2cf7b..52e5b023db0 100644 --- a/src/core/lib/transport/hashtable.h +++ b/src/core/lib/transport/mdstr_hash_table.h @@ -29,8 +29,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef GRPC_CORE_LIB_TRANSPORT_HASHTABLE_H -#define GRPC_CORE_LIB_TRANSPORT_HASHTABLE_H +#ifndef GRPC_CORE_LIB_TRANSPORT_MDSTR_HASH_TABLE_H +#define GRPC_CORE_LIB_TRANSPORT_MDSTR_HASH_TABLE_H #include "src/core/lib/transport/metadata.h" @@ -46,37 +46,38 @@ * Hash tables are intentionally immutable, to avoid the need for locking. */ -typedef struct grpc_hash_table grpc_hash_table; +typedef struct grpc_mdstr_hash_table grpc_mdstr_hash_table; -typedef struct grpc_hash_table_vtable { +typedef struct grpc_mdstr_hash_table_vtable { void (*destroy_value)(void* value); void* (*copy_value)(void* value); int (*compare_value)(void* value1, void* value2); -} grpc_hash_table_vtable; +} grpc_mdstr_hash_table_vtable; -typedef struct grpc_hash_table_entry { +typedef struct grpc_mdstr_hash_table_entry { grpc_mdstr* key; void* value; /* Must not be NULL. */ - const grpc_hash_table_vtable* vtable; -} grpc_hash_table_entry; + const grpc_mdstr_hash_table_vtable* vtable; +} grpc_mdstr_hash_table_entry; /** Creates a new hash table of containing \a entries, which is an array of length \a num_entries. Creates its own copy of all keys and values from \a entries. */ -grpc_hash_table* grpc_hash_table_create(size_t num_entries, - grpc_hash_table_entry* entries); +grpc_mdstr_hash_table* grpc_mdstr_hash_table_create( + size_t num_entries, grpc_mdstr_hash_table_entry* entries); -grpc_hash_table* grpc_hash_table_ref(grpc_hash_table* table); +grpc_mdstr_hash_table* grpc_mdstr_hash_table_ref(grpc_mdstr_hash_table* table); /** Returns 1 when \a table is destroyed. */ -int grpc_hash_table_unref(grpc_hash_table* table); +int grpc_mdstr_hash_table_unref(grpc_mdstr_hash_table* table); /** Returns the value from \a table associated with \a key. Returns NULL if \a key is not found. */ -void* grpc_hash_table_get(const grpc_hash_table* table, const grpc_mdstr* key); +void* grpc_mdstr_hash_table_get(const grpc_mdstr_hash_table* table, + const grpc_mdstr* key); /** Compares two hash tables. The sort order is stable but undefined. */ -int grpc_hash_table_cmp(const grpc_hash_table* table1, - const grpc_hash_table* table2); +int grpc_mdstr_hash_table_cmp(const grpc_mdstr_hash_table* table1, + const grpc_mdstr_hash_table* table2); -#endif /* GRPC_CORE_LIB_TRANSPORT_HASHTABLE_H */ +#endif /* GRPC_CORE_LIB_TRANSPORT_MDSTR_HASH_TABLE_H */ diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py index 315d469a153..98bbe6f7427 100644 --- a/src/python/grpcio/grpc_core_dependencies.py +++ b/src/python/grpcio/grpc_core_dependencies.py @@ -164,7 +164,7 @@ CORE_SOURCE_FILES = [ 'src/core/lib/surface/version.c', 'src/core/lib/transport/byte_stream.c', 'src/core/lib/transport/connectivity_state.c', - 'src/core/lib/transport/hashtable.c', + 'src/core/lib/transport/mdstr_hash_table.c', 'src/core/lib/transport/metadata.c', 'src/core/lib/transport/metadata_batch.c', 'src/core/lib/transport/static_metadata.c', diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal index c9317396f61..0a2a3456f16 100644 --- a/tools/doxygen/Doxyfile.core.internal +++ b/tools/doxygen/Doxyfile.core.internal @@ -863,7 +863,7 @@ src/core/lib/surface/lame_client.h \ src/core/lib/surface/server.h \ src/core/lib/transport/byte_stream.h \ src/core/lib/transport/connectivity_state.h \ -src/core/lib/transport/hashtable.h \ +src/core/lib/transport/mdstr_hash_table.h \ src/core/lib/transport/metadata.h \ src/core/lib/transport/metadata_batch.h \ src/core/lib/transport/static_metadata.h \ @@ -1039,7 +1039,7 @@ src/core/lib/surface/validate_metadata.c \ src/core/lib/surface/version.c \ src/core/lib/transport/byte_stream.c \ src/core/lib/transport/connectivity_state.c \ -src/core/lib/transport/hashtable.c \ +src/core/lib/transport/mdstr_hash_table.c \ src/core/lib/transport/metadata.c \ src/core/lib/transport/metadata_batch.c \ src/core/lib/transport/static_metadata.c \ diff --git a/tools/run_tests/sources_and_headers.json b/tools/run_tests/sources_and_headers.json index 2ca9ed60006..e0b8a0902a6 100644 --- a/tools/run_tests/sources_and_headers.json +++ b/tools/run_tests/sources_and_headers.json @@ -6463,7 +6463,7 @@ "src/core/lib/surface/server.h", "src/core/lib/transport/byte_stream.h", "src/core/lib/transport/connectivity_state.h", - "src/core/lib/transport/hashtable.h", + "src/core/lib/transport/mdstr_hash_table.h", "src/core/lib/transport/metadata.h", "src/core/lib/transport/metadata_batch.h", "src/core/lib/transport/static_metadata.h", @@ -6645,8 +6645,8 @@ "src/core/lib/transport/byte_stream.h", "src/core/lib/transport/connectivity_state.c", "src/core/lib/transport/connectivity_state.h", - "src/core/lib/transport/hashtable.c", - "src/core/lib/transport/hashtable.h", + "src/core/lib/transport/mdstr_hash_table.c", + "src/core/lib/transport/mdstr_hash_table.h", "src/core/lib/transport/metadata.c", "src/core/lib/transport/metadata.h", "src/core/lib/transport/metadata_batch.c", diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj b/vsprojects/vcxproj/grpc/grpc.vcxproj index b2352d74f45..2297e81fbf5 100644 --- a/vsprojects/vcxproj/grpc/grpc.vcxproj +++ b/vsprojects/vcxproj/grpc/grpc.vcxproj @@ -372,7 +372,7 @@ - + @@ -637,7 +637,7 @@ - + diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters index ee7825ae882..3e8632daa57 100644 --- a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters +++ b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters @@ -262,7 +262,7 @@ src\core\lib\transport - + src\core\lib\transport @@ -905,7 +905,7 @@ src\core\lib\transport - + src\core\lib\transport diff --git a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj index c7375431c84..f9602d03495 100644 --- a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj +++ b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj @@ -265,7 +265,7 @@ - + @@ -484,7 +484,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 18cdaa58195..412af4d5afd 100644 --- a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters +++ b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters @@ -316,7 +316,7 @@ src\core\lib\transport - + src\core\lib\transport @@ -689,7 +689,7 @@ src\core\lib\transport - + src\core\lib\transport diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj index 09a1e2386d5..730d17beeea 100644 --- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj +++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj @@ -362,7 +362,7 @@ - + @@ -605,7 +605,7 @@ - + diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters index df7a9b9b432..235dc993f15 100644 --- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters +++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters @@ -265,7 +265,7 @@ src\core\lib\transport - + src\core\lib\transport @@ -815,7 +815,7 @@ src\core\lib\transport - + src\core\lib\transport From ff08f33e094640caf8e8ce5d8d2a2f82c3cc4f3b Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Fri, 14 Oct 2016 13:01:01 -0700 Subject: [PATCH 39/48] Pass call start time into the call stack via grpc_call_element_args. --- src/core/ext/census/grpc_filter.c | 4 ++-- src/core/ext/client_config/client_channel.c | 4 +--- src/core/lib/channel/channel_stack.c | 1 + src/core/lib/channel/channel_stack.h | 1 + 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/core/ext/census/grpc_filter.c b/src/core/ext/census/grpc_filter.c index 9dacc17eb4a..a4cf6f37bd7 100644 --- a/src/core/ext/census/grpc_filter.c +++ b/src/core/ext/census/grpc_filter.c @@ -133,7 +133,7 @@ static grpc_error *client_init_call_elem(grpc_exec_ctx *exec_ctx, call_data *d = elem->call_data; GPR_ASSERT(d != NULL); memset(d, 0, sizeof(*d)); - d->start_ts = gpr_now(GPR_CLOCK_REALTIME); + d->start_ts = args->start_time; return GRPC_ERROR_NONE; } @@ -152,7 +152,7 @@ static grpc_error *server_init_call_elem(grpc_exec_ctx *exec_ctx, call_data *d = elem->call_data; GPR_ASSERT(d != NULL); memset(d, 0, sizeof(*d)); - d->start_ts = gpr_now(GPR_CLOCK_REALTIME); + d->start_ts = args->start_time; /* TODO(hongyu): call census_tracing_start_op here. */ grpc_closure_init(&d->finish_recv, server_on_done_recv, elem); return GRPC_ERROR_NONE; diff --git a/src/core/ext/client_config/client_channel.c b/src/core/ext/client_config/client_channel.c index fb3e17a7d9f..0ad9278d4f7 100644 --- a/src/core/ext/client_config/client_channel.c +++ b/src/core/ext/client_config/client_channel.c @@ -881,9 +881,7 @@ static grpc_error *cc_init_call_elem(grpc_exec_ctx *exec_ctx, // Initialize data members. grpc_deadline_state_init(exec_ctx, elem, args->call_stack); calld->path = GRPC_MDSTR_REF(args->path); - // TODO(roth): Is there a better value to use here for the actual start - // time of the call (i.e., something initialized at the surface layer)? - calld->call_start_time = gpr_now(GPR_CLOCK_MONOTONIC); + calld->call_start_time = args->start_time; calld->deadline = gpr_convert_clock_type(args->deadline, GPR_CLOCK_MONOTONIC); calld->wait_for_ready_from_service_config = WAIT_FOR_READY_UNSET; calld->cancel_error = GRPC_ERROR_NONE; diff --git a/src/core/lib/channel/channel_stack.c b/src/core/lib/channel/channel_stack.c index 205496f2f26..2c5367901df 100644 --- a/src/core/lib/channel/channel_stack.c +++ b/src/core/lib/channel/channel_stack.c @@ -179,6 +179,7 @@ grpc_error *grpc_call_stack_init( /* init per-filter data */ grpc_error *first_error = GRPC_ERROR_NONE; + args.start_time = gpr_now(GPR_CLOCK_MONOTONIC); for (i = 0; i < count; i++) { args.call_stack = call_stack; args.server_transport_data = transport_server_data; diff --git a/src/core/lib/channel/channel_stack.h b/src/core/lib/channel/channel_stack.h index 5b46cd32a3a..27f3be7b291 100644 --- a/src/core/lib/channel/channel_stack.h +++ b/src/core/lib/channel/channel_stack.h @@ -75,6 +75,7 @@ typedef struct { const void *server_transport_data; grpc_call_context_element *context; grpc_mdstr *path; + gpr_timespec start_time; gpr_timespec deadline; } grpc_call_element_args; From f72ead33328984986f4f6f0edc4f3a87faa6d362 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Tue, 18 Oct 2016 19:02:46 +0200 Subject: [PATCH 40/48] refactor NoSuchMethodCallHandler --- .../Grpc.Core/Internal/ServerCallHandler.cs | 33 ++++++++++++------- src/csharp/Grpc.Core/Server.cs | 2 +- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs b/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs index 6a2f5201636..ebb7e0021eb 100644 --- a/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs +++ b/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs @@ -277,20 +277,31 @@ namespace Grpc.Core.Internal } } - internal class NoSuchMethodCallHandler : IServerCallHandler + internal class UnimplementedMethodCallHandler : IServerCallHandler { - public static readonly NoSuchMethodCallHandler Instance = new NoSuchMethodCallHandler(); + public static readonly UnimplementedMethodCallHandler Instance = new UnimplementedMethodCallHandler(); - public async Task HandleCall(ServerRpcNew newRpc, CompletionQueueSafeHandle cq) + DuplexStreamingServerCallHandler callHandlerImpl; + + public UnimplementedMethodCallHandler() { - // We don't care about the payload type here. - var asyncCall = new AsyncCallServer( - (payload) => payload, (payload) => payload, newRpc.Server); - - asyncCall.Initialize(newRpc.Call, cq); - var finishedTask = asyncCall.ServerSideCallAsync(); - await asyncCall.SendStatusFromServerAsync(new Status(StatusCode.Unimplemented, ""), Metadata.Empty, null).ConfigureAwait(false); - await finishedTask.ConfigureAwait(false); + var marshaller = new Marshaller((payload) => payload, (payload) => payload); + var method = new Method(MethodType.DuplexStreaming, "", "", marshaller, marshaller); + this.callHandlerImpl = new DuplexStreamingServerCallHandler(method, new DuplexStreamingServerMethod(UnimplementedMethod)); + } + + /// + /// Handler used for unimplemented method. + /// + private Task UnimplementedMethod(IAsyncStreamReader requestStream, IServerStreamWriter responseStream, ServerCallContext ctx) + { + ctx.Status = new Status(StatusCode.Unimplemented, ""); + return Task.FromResult(null); + } + + public Task HandleCall(ServerRpcNew newRpc, CompletionQueueSafeHandle cq) + { + return callHandlerImpl.HandleCall(newRpc, cq); } } diff --git a/src/csharp/Grpc.Core/Server.cs b/src/csharp/Grpc.Core/Server.cs index 3b554e5e87e..dd4a405ed92 100644 --- a/src/csharp/Grpc.Core/Server.cs +++ b/src/csharp/Grpc.Core/Server.cs @@ -317,7 +317,7 @@ namespace Grpc.Core IServerCallHandler callHandler; if (!callHandlers.TryGetValue(newRpc.Method, out callHandler)) { - callHandler = NoSuchMethodCallHandler.Instance; + callHandler = UnimplementedMethodCallHandler.Instance; } await callHandler.HandleCall(newRpc, cq).ConfigureAwait(false); } From 88477fd046e5fd518750cdf7ba5873b95f02fdd9 Mon Sep 17 00:00:00 2001 From: Noah Eisen Date: Tue, 18 Oct 2016 12:25:25 -0700 Subject: [PATCH 41/48] All current interop tests are implemented for C++ client and server. Updated run_interop_tests.py so that C++ no longer skips any tests --- tools/run_tests/run_interop_tests.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/run_tests/run_interop_tests.py b/tools/run_tests/run_interop_tests.py index aa246f204a6..29f65333983 100755 --- a/tools/run_tests/run_interop_tests.py +++ b/tools/run_tests/run_interop_tests.py @@ -64,9 +64,9 @@ _SKIP_SERVER_COMPRESSION = ['server_compressed_unary', _SKIP_COMPRESSION = _SKIP_CLIENT_COMPRESSION + _SKIP_SERVER_COMPRESSION -_SKIP_ADVANCED_CXX_AND_GO = ['custom_metadata', 'unimplemented_method'] +_SKIP_ADVANCED_GO = ['custom_metadata', 'unimplemented_method'] -_SKIP_ADVANCED = _SKIP_ADVANCED_CXX_AND_GO + ['status_code_and_message'] +_SKIP_ADVANCED = _SKIP_ADVANCED_GO + ['status_code_and_message'] _TEST_TIMEOUT = 3*60 @@ -90,10 +90,10 @@ class CXXLanguage: return {} def unimplemented_test_cases(self): - return _SKIP_ADVANCED_CXX_AND_GO + return [] def unimplemented_test_cases_server(self): - return _SKIP_ADVANCED_CXX_AND_GO + return [] def __str__(self): return 'c++' @@ -207,10 +207,10 @@ class GoLanguage: return {} def unimplemented_test_cases(self): - return _SKIP_ADVANCED_CXX_AND_GO + _SKIP_COMPRESSION + return _SKIP_ADVANCED_GO + _SKIP_COMPRESSION def unimplemented_test_cases_server(self): - return _SKIP_ADVANCED_CXX_AND_GO + _SKIP_COMPRESSION + return _SKIP_ADVANCED_GO + _SKIP_COMPRESSION def __str__(self): return 'go' From 667301a25fc6ac47923e9c184754117ec1ff9a58 Mon Sep 17 00:00:00 2001 From: Ken Payson Date: Tue, 18 Oct 2016 11:42:10 -0700 Subject: [PATCH 42/48] Change channel tests to use public API This allows for testing other implementations of grpc.Server. --- .../tests/unit/_channel_connectivity_test.py | 12 +++++------- .../tests/unit/_channel_ready_future_test.py | 4 +--- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/python/grpcio_tests/tests/unit/_channel_connectivity_test.py b/src/python/grpcio_tests/tests/unit/_channel_connectivity_test.py index 1324ad37b6d..3d9dd17ff68 100644 --- a/src/python/grpcio_tests/tests/unit/_channel_connectivity_test.py +++ b/src/python/grpcio_tests/tests/unit/_channel_connectivity_test.py @@ -34,8 +34,6 @@ import time import unittest import grpc -from grpc import _channel -from grpc import _server from tests.unit.framework.common import test_constants from tests.unit import _thread_pool @@ -78,7 +76,7 @@ class ChannelConnectivityTest(unittest.TestCase): def test_lonely_channel_connectivity(self): callback = _Callback() - channel = _channel.Channel('localhost:12345', (), None) + channel = grpc.insecure_channel('localhost:12345') channel.subscribe(callback.update, try_to_connect=False) first_connectivities = callback.block_until_connectivities_satisfy(bool) channel.subscribe(callback.update, try_to_connect=True) @@ -105,13 +103,13 @@ class ChannelConnectivityTest(unittest.TestCase): def test_immediately_connectable_channel_connectivity(self): thread_pool = _thread_pool.RecordingThreadPool(max_workers=None) - server = _server.Server(thread_pool, (), ()) + server = grpc.server(thread_pool) port = server.add_insecure_port('[::]:0') server.start() first_callback = _Callback() second_callback = _Callback() - channel = _channel.Channel('localhost:{}'.format(port), (), None) + channel = grpc.insecure_channel('localhost:{}'.format(port)) channel.subscribe(first_callback.update, try_to_connect=False) first_connectivities = first_callback.block_until_connectivities_satisfy( bool) @@ -146,12 +144,12 @@ class ChannelConnectivityTest(unittest.TestCase): def test_reachable_then_unreachable_channel_connectivity(self): thread_pool = _thread_pool.RecordingThreadPool(max_workers=None) - server = _server.Server(thread_pool, (), ()) + server = grpc.server(thread_pool) port = server.add_insecure_port('[::]:0') server.start() callback = _Callback() - channel = _channel.Channel('localhost:{}'.format(port), (), None) + channel = grpc.insecure_channel('localhost:{}'.format(port)) channel.subscribe(callback.update, try_to_connect=True) callback.block_until_connectivities_satisfy(_ready_in_connectivities) # Now take down the server and confirm that channel readiness is repudiated. diff --git a/src/python/grpcio_tests/tests/unit/_channel_ready_future_test.py b/src/python/grpcio_tests/tests/unit/_channel_ready_future_test.py index 60d478bcd96..e0a7d15aa76 100644 --- a/src/python/grpcio_tests/tests/unit/_channel_ready_future_test.py +++ b/src/python/grpcio_tests/tests/unit/_channel_ready_future_test.py @@ -33,8 +33,6 @@ import threading import unittest import grpc -from grpc import _channel -from grpc import _server from tests.unit.framework.common import test_constants from tests.unit import _thread_pool @@ -79,7 +77,7 @@ class ChannelReadyFutureTest(unittest.TestCase): def test_immediately_connectable_channel_connectivity(self): thread_pool = _thread_pool.RecordingThreadPool(max_workers=None) - server = _server.Server(thread_pool, (), ()) + server = grpc.server(thread_pool) port = server.add_insecure_port('[::]:0') server.start() channel = grpc.insecure_channel('localhost:{}'.format(port)) From 6e104d9630d64c280756e6c1d0cadae5946b4e1f Mon Sep 17 00:00:00 2001 From: Sree Kuchibhotla Date: Tue, 18 Oct 2016 13:05:17 -0700 Subject: [PATCH 43/48] epoll design doc --- doc/epoll-polling-engine.md | 121 ++++++++++++++++++++++++++++++++++ doc/images/new_epoll_impl.png | Bin 0 -> 53823 bytes doc/images/old_epoll_impl.png | Bin 0 -> 44262 bytes 3 files changed, 121 insertions(+) create mode 100644 doc/epoll-polling-engine.md create mode 100644 doc/images/new_epoll_impl.png create mode 100644 doc/images/old_epoll_impl.png diff --git a/doc/epoll-polling-engine.md b/doc/epoll-polling-engine.md new file mode 100644 index 00000000000..ab7030a211d --- /dev/null +++ b/doc/epoll-polling-engine.md @@ -0,0 +1,121 @@ +# `epoll`-based pollset implementation in gRPC + +Sree Kuchibhotla (sreek@) [May - 2016] +(Design input from Craig Tiller and David Klempner) + +> Status: As of June 2016, this change is implemented and merged. + +> * The bulk of the functionality is in: [ev_poll_linux.c](https://github.com/grpc/grpc/blob/master/src/core/lib/iomgr/ev_epoll_linux.c) +> * Pull request: https://github.com/grpc/grpc/pull/6803 + +## 1. Introduction +The document talks about the proposed changes to `epoll`-based implementation of pollsets in gRPC. Section-2 gives an overview of the current implementation, Section-3 talks about the problems in the current implementation and finally Section-4 talks about the proposed changes. + +## 2. Current `epoll`-based implementation in gRPC + +![image](images/old_epoll_impl.png) + +**Figure 1: Current implementation** + +A gRPC client or a server can have more than one completion queue. Each completion queue creates a pollset. + +The gRPC core library does not create any threads[^1] on its own and relies on the application using the gRPC core library to provide the threads. A thread starts to poll for events by calling the gRPC core surface APIs `grpc_completion_queue_next()` or `grpc_completion_queue_pluck()`. More than one thread can call `grpc_completion_queue_next()`on the same completion queue[^2]. + +A file descriptor can be in more than one completion queue. There are examples in the next section that show how this can happen. + +When an event of interest happens in a pollset, multiple threads are woken up and there are no guarantees on which thread actually ends up performing the work i.e executing the callbacks associated with that event. The thread that performs the work finally queues a completion event `grpc_cq_completion` on the appropriate completion queue and "kicks" (i.e wakes ups) the thread that is actually interested in that event (which can be itself - in which case there is no thread hop) + +For example, in **Figure 1**, if `fd1` becomes readable, any one of the threads i.e *Threads 1* to *Threads K* or *Thread P*, might be woken up. Let's say *Thread P* was calling a `grpc_completion_queue_pluck()` and was actually interested in the event on `fd1` but *Thread 1* woke up. In this case, *Thread 1* executes the callbacks and finally kicks *Thread P* by signalling `event_fd_P`. *Thread P* wakes up, realizes that there is a new completion event for it and returns from `grpc_completion_queue_pluck()` to its caller. + +## 3. Issues in the current architecture + +### _Thundering Herds_ + +If multiple threads concurrently call `epoll_wait()`, we are guaranteed that only one thread is woken up if one of the `fds` in the set becomes readable/writable. However, in our current implementation, the threads do not directly call a blocking `epoll_wait()`[^3]. Instead, they call `poll()` on the set containing `[event_fd`[^4]`, epoll_fd]`. **(see Figure 1)** + +Considering the fact that an `fd` can be in multiple `pollsets` and that each `pollset` might have multiple poller threads, it means that whenever an `fd` becomes readable/writable, all the threads in all the `pollsets` (in which that `fd` is present) are woken up. + +The performance impact of this would be more conspicuous on the server side. Here are a two examples of thundering herds on the server side. + +Example 1: Listening fds on server + +* A gRPC server can have multiple server completion queues (i.e completion queues which are used to listen for incoming channels). +* A gRPC server can also listen on more than one TCP-port. +* A listening socket is created for each port the gRPC server would be listening on. +* Every listening socket's fd is added to all the server completion queues' pollsets. (Currently we do not do any sharding of the listening fds across these pollsets). + +This means that for every incoming new channel, all the threads waiting on all the pollsets are woken up. + +Example 2: New Incoming-channel fds on server + +* Currently, every new incoming channel's `fd` (i.e the socket `fd` that is returned by doing an `accept()` on the new incoming channel) is added to all the server completion queues' pollsets [^5]). +* Clearly, this would also cause all thundering herd problem for every read onthat fd + +There are other scenarios especially on the client side where an fd can end up being on multiple pollsets which would cause thundering herds on the clients. + + +## 4. Proposed changes to the current `epoll`-based polling implementation: + +The main idea in this proposal is to group 'related' `fds` into a single epoll-based set. This would ensure that only one thread wakes up in case of an event on one of the `fds` in the epoll set. + +To accomplish this, we introduce a new abstraction called `polling_island` which will have an epoll set underneath (See **Figure 2** below). A `polling_island` contains the following: + +* `epoll_fd`: The file descriptor of the underlying epoll set +* `fd_set`: The set of 'fds' in the pollset island i.e in the epoll set (The pollset island merging operation described later requires the list of fds in the pollset island and currently there is no API available to enumerate all the fds in an epoll set) +* `event_fd`: A level triggered _event fd_ that is used to wake up all the threads waiting on this epoll set (Note: This `event_fd` is added to the underlying epoll set during pollset island creation. This is useful in the pollset island merging operation described later) +* `merged_to`: The polling island into which this one merged. See section 4.2 (case 2) for more details on this. Also note that if `merged_to` is set, all the other fields in this polling island are not used anymore + +In this new model, only one thread wakes up whenever an event of interest happens in an epoll set. + +![drawing](images/new_epoll_impl.png) + +**Figure 2: Proposed changes** + +### 4.1 Relation between `fd`, `pollset` and `polling_island:` + +* An `fd` may belong to multiple `pollsets` but belongs to exactly one `polling_island` +* A `pollset` belongs to exactly one `polling_island` +* An `fd` and the `pollset(s`) it belongs to, have same `polling_island` + +### 4.2 Algorithm to add an `fd` to a `pollset` + +There are two cases to check here: + +* **Case 1:** Both `fd` and `pollset` already belong to the same `polling_island` + * This is straightforward and nothing really needs to be done here +* **Case 2:** The `fd `and `pollset` point to different `polling_islands`: In this case we _merge_ both the polling islands i.e: + * Add all the `fds` from the smaller `polling_island `to the larger `polling_island` and update the `merged_to` pointer on the smaller island to point to the larger island. + * Wake up all the threads waiting on the smaller `polling_island`'s `epoll_fd` (by signalling the `event_fd` on that island) and make them now wait on the larger `polling_island`'s `epoll_fd` + * Update `fd` and `pollset` to now point to the larger `polling_island` + +### 4.3 Directed wakeups: + +The new implementation, just like the current implementation, does not provide us any guarantees that the thread that is woken up is the thread that is actually interested in the event. So the thread that woke up executes the callbacks and finally has to 'kick' the appropriate polling thread interested in the event. + +In the current implementation, every polling thread also had a `event_fd` on which it was listening to and hence waking it up was as simple as signalling that `event_fd`. However, using an `event_fd` also meant that every thread has to use a `poll()` (on `event_fd` and `epoll_fd`) instead of doing an `epoll_wait()` and this resulted in the thundering herd problems described above. + +The proposal here is to use signals and kicking a thread would just be sending a signal to that thread. Unfortunately there are only a few signals available on posix systems and most of them have pre-determined behavior leaving only a few signals `SIGUSR1`, `SIGUSR2` and `SIGRTx (SIGRTMIN to SIGRTMAX)` for custom use. + +The calling application might have registered other signal handlers for these signals. `We will provide a new API where the applications can "give a signal number" to gRPC library to use for this purpose. + +``` +void grpc_use_signal(int signal_num) +``` + +If the calling application does not provide a signal number, then the gRPC library will relegate to using a model similar to the current implementation (where every thread does a blocking `poll()` on its `wakeup_fd` and the `epoll_fd`). The function` psi_wait() `in figure 2 implements this logic. + +**>> **(**NOTE**: Or alternatively, we can implement a turnstile polling (i.e having only one thread calling `epoll_wait()` on the epoll set at any time - which all other threads call poll on their `wakeup_fds`) +in case of not getting a signal number from the applications. + + +## Notes + +[^1]: Only exception is in case of name-resolution + +[^2]: However, a `grpc_completion_queue_next()` and `grpc_completion_queue_pluck()` must not be called in parallel on the same completion queue + +[^3]: The threads first do a blocking` poll()` with `[wakeup_fd, epoll_fd]`. If the `poll()` returns due to an event of interest in the epoll set, they then call a non-blocking i.e a zero-timeout `epoll_wait()` on the `epoll_fd` + +[^4]: `event_fd` is the linux platform specific implementation of `grpc_wakeup_fd`. A `wakeup_fd` is used to wake up polling threads typically when the event for which the polling thread is waiting is already completed by some other thread. It is also used to wake up the polling threads in case of shutdowns or to re-evaluate the poller's interest in the fds to poll (the last scenario is only in case of `poll`-based (not `epoll`-based) implementation of `pollsets`). + +[^5]: See more details about the issue here https://github.com/grpc/grpc/issues/5470 and for a proposed fix here: https://github.com/grpc/grpc/pull/6149 diff --git a/doc/images/new_epoll_impl.png b/doc/images/new_epoll_impl.png new file mode 100644 index 0000000000000000000000000000000000000000..2310e62c70d8f7e6e2a380bd5ac3bacada64db3f GIT binary patch literal 53823 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 WAI`zpngR!gyfs}bI{7DNoHv`+bQL{M;2K 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 MUHx3vIVCg!0L?3VApigX literal 0 HcmV?d00001 diff --git a/doc/images/old_epoll_impl.png b/doc/images/old_epoll_impl.png new file mode 100644 index 0000000000000000000000000000000000000000..05da838a3fbb74270cc8e13389c3bab98b3f6e31 GIT binary patch literal 44262 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 Date: Tue, 18 Oct 2016 13:20:43 -0700 Subject: [PATCH 44/48] update images --- doc/images/new_epoll_impl.png | Bin 53823 -> 53699 bytes doc/images/old_epoll_impl.png | Bin 44262 -> 45342 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/doc/images/new_epoll_impl.png b/doc/images/new_epoll_impl.png index 2310e62c70d8f7e6e2a380bd5ac3bacada64db3f..9ca1f49cbdb290eca0493a491fef57f608c1962a 100644 GIT binary patch literal 53699 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 literal 53823 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 WAI`zpngR!gyfs}bI{7DNoHv`+bQL{M;2K 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 MUHx3vIVCg!0L?3VApigX diff --git a/doc/images/old_epoll_impl.png b/doc/images/old_epoll_impl.png index 05da838a3fbb74270cc8e13389c3bab98b3f6e31..7ac3df83674c1f22631c12cf9d9bf78a2585610f 100644 GIT binary patch literal 45342 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 Date: Wed, 19 Oct 2016 07:45:22 -0700 Subject: [PATCH 45/48] clang-format --- src/core/lib/surface/call.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/core/lib/surface/call.c b/src/core/lib/surface/call.c index 24534104d38..30559304c6e 100644 --- a/src/core/lib/surface/call.c +++ b/src/core/lib/surface/call.c @@ -310,10 +310,10 @@ grpc_error *grpc_call_create(const grpc_call_create_args *args, GRPC_CHANNEL_INTERNAL_REF(args->channel, "call"); /* initial refcount dropped by grpc_call_destroy */ - grpc_error *error = grpc_call_stack_init( - &exec_ctx, channel_stack, 1, destroy_call, call, call->context, - args->server_transport_data, path, send_deadline, - CALL_STACK_FROM_CALL(call)); + grpc_error *error = + grpc_call_stack_init(&exec_ctx, channel_stack, 1, destroy_call, call, + call->context, args->server_transport_data, path, + send_deadline, CALL_STACK_FROM_CALL(call)); if (error != GRPC_ERROR_NONE) { grpc_status_code status; const char *error_str; From 2dc4968b93abde382e31e9b47af09e564c4e1451 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 19 Oct 2016 08:47:32 -0700 Subject: [PATCH 46/48] Fix config-exclusion for secure variants of tests --- test/core/end2end/gen_build_yaml.py | 2 +- tools/run_tests/tests.json | 156 +++++++++++++++++++++------- 2 files changed, 118 insertions(+), 40 deletions(-) diff --git a/test/core/end2end/gen_build_yaml.py b/test/core/end2end/gen_build_yaml.py index 78b37efd372..fbeca7e1c5a 100755 --- a/test/core/end2end/gen_build_yaml.py +++ b/test/core/end2end/gen_build_yaml.py @@ -245,7 +245,7 @@ def main(): { 'name': '%s_test' % f, 'args': [t], - 'exclude_configs': [], + 'exclude_configs': END2END_FIXTURES[f].exclude_configs, 'platforms': END2END_FIXTURES[f].platforms, 'ci_platforms': (END2END_FIXTURES[f].platforms if END2END_FIXTURES[f].ci_mac else without( diff --git a/tools/run_tests/tests.json b/tools/run_tests/tests.json index 40955999265..392c9074a76 100644 --- a/tools/run_tests/tests.json +++ b/tools/run_tests/tests.json @@ -16034,7 +16034,9 @@ "posix" ], "cpu_cost": 1.0, - "exclude_configs": [], + "exclude_configs": [ + "msan" + ], "flaky": false, "language": "c", "name": "h2_sockpair_1byte_test", @@ -16055,7 +16057,9 @@ "posix" ], "cpu_cost": 1.0, - "exclude_configs": [], + "exclude_configs": [ + "msan" + ], "flaky": false, "language": "c", "name": "h2_sockpair_1byte_test", @@ -16076,7 +16080,9 @@ "posix" ], "cpu_cost": 1.0, - "exclude_configs": [], + "exclude_configs": [ + "msan" + ], "flaky": false, "language": "c", "name": "h2_sockpair_1byte_test", @@ -16097,7 +16103,9 @@ "posix" ], "cpu_cost": 0.1, - "exclude_configs": [], + "exclude_configs": [ + "msan" + ], "flaky": false, "language": "c", "name": "h2_sockpair_1byte_test", @@ -16118,7 +16126,9 @@ "posix" ], "cpu_cost": 1.0, - "exclude_configs": [], + "exclude_configs": [ + "msan" + ], "flaky": false, "language": "c", "name": "h2_sockpair_1byte_test", @@ -16139,7 +16149,9 @@ "posix" ], "cpu_cost": 0.1, - "exclude_configs": [], + "exclude_configs": [ + "msan" + ], "flaky": false, "language": "c", "name": "h2_sockpair_1byte_test", @@ -16160,7 +16172,9 @@ "posix" ], "cpu_cost": 0.1, - "exclude_configs": [], + "exclude_configs": [ + "msan" + ], "flaky": false, "language": "c", "name": "h2_sockpair_1byte_test", @@ -16181,7 +16195,9 @@ "posix" ], "cpu_cost": 0.1, - "exclude_configs": [], + "exclude_configs": [ + "msan" + ], "flaky": false, "language": "c", "name": "h2_sockpair_1byte_test", @@ -16202,7 +16218,9 @@ "posix" ], "cpu_cost": 0.1, - "exclude_configs": [], + "exclude_configs": [ + "msan" + ], "flaky": false, "language": "c", "name": "h2_sockpair_1byte_test", @@ -16223,7 +16241,9 @@ "posix" ], "cpu_cost": 1.0, - "exclude_configs": [], + "exclude_configs": [ + "msan" + ], "flaky": false, "language": "c", "name": "h2_sockpair_1byte_test", @@ -16244,7 +16264,9 @@ "posix" ], "cpu_cost": 1.0, - "exclude_configs": [], + "exclude_configs": [ + "msan" + ], "flaky": false, "language": "c", "name": "h2_sockpair_1byte_test", @@ -16265,7 +16287,9 @@ "posix" ], "cpu_cost": 1.0, - "exclude_configs": [], + "exclude_configs": [ + "msan" + ], "flaky": false, "language": "c", "name": "h2_sockpair_1byte_test", @@ -16286,7 +16310,9 @@ "posix" ], "cpu_cost": 1.0, - "exclude_configs": [], + "exclude_configs": [ + "msan" + ], "flaky": false, "language": "c", "name": "h2_sockpair_1byte_test", @@ -16307,7 +16333,9 @@ "posix" ], "cpu_cost": 0.1, - "exclude_configs": [], + "exclude_configs": [ + "msan" + ], "flaky": false, "language": "c", "name": "h2_sockpair_1byte_test", @@ -16328,7 +16356,9 @@ "posix" ], "cpu_cost": 1.0, - "exclude_configs": [], + "exclude_configs": [ + "msan" + ], "flaky": false, "language": "c", "name": "h2_sockpair_1byte_test", @@ -16349,7 +16379,9 @@ "posix" ], "cpu_cost": 1.0, - "exclude_configs": [], + "exclude_configs": [ + "msan" + ], "flaky": false, "language": "c", "name": "h2_sockpair_1byte_test", @@ -16370,7 +16402,9 @@ "posix" ], "cpu_cost": 1.0, - "exclude_configs": [], + "exclude_configs": [ + "msan" + ], "flaky": false, "language": "c", "name": "h2_sockpair_1byte_test", @@ -16391,7 +16425,9 @@ "posix" ], "cpu_cost": 1.0, - "exclude_configs": [], + "exclude_configs": [ + "msan" + ], "flaky": false, "language": "c", "name": "h2_sockpair_1byte_test", @@ -16412,7 +16448,9 @@ "posix" ], "cpu_cost": 1.0, - "exclude_configs": [], + "exclude_configs": [ + "msan" + ], "flaky": false, "language": "c", "name": "h2_sockpair_1byte_test", @@ -16433,7 +16471,9 @@ "posix" ], "cpu_cost": 1.0, - "exclude_configs": [], + "exclude_configs": [ + "msan" + ], "flaky": false, "language": "c", "name": "h2_sockpair_1byte_test", @@ -16454,7 +16494,9 @@ "posix" ], "cpu_cost": 1.0, - "exclude_configs": [], + "exclude_configs": [ + "msan" + ], "flaky": false, "language": "c", "name": "h2_sockpair_1byte_test", @@ -16475,7 +16517,9 @@ "posix" ], "cpu_cost": 1.0, - "exclude_configs": [], + "exclude_configs": [ + "msan" + ], "flaky": false, "language": "c", "name": "h2_sockpair_1byte_test", @@ -16496,7 +16540,9 @@ "posix" ], "cpu_cost": 1.0, - "exclude_configs": [], + "exclude_configs": [ + "msan" + ], "flaky": false, "language": "c", "name": "h2_sockpair_1byte_test", @@ -16517,7 +16563,9 @@ "posix" ], "cpu_cost": 1.0, - "exclude_configs": [], + "exclude_configs": [ + "msan" + ], "flaky": false, "language": "c", "name": "h2_sockpair_1byte_test", @@ -16538,7 +16586,9 @@ "posix" ], "cpu_cost": 1.0, - "exclude_configs": [], + "exclude_configs": [ + "msan" + ], "flaky": false, "language": "c", "name": "h2_sockpair_1byte_test", @@ -16559,7 +16609,9 @@ "posix" ], "cpu_cost": 1.0, - "exclude_configs": [], + "exclude_configs": [ + "msan" + ], "flaky": false, "language": "c", "name": "h2_sockpair_1byte_test", @@ -16580,7 +16632,9 @@ "posix" ], "cpu_cost": 1.0, - "exclude_configs": [], + "exclude_configs": [ + "msan" + ], "flaky": false, "language": "c", "name": "h2_sockpair_1byte_test", @@ -16601,7 +16655,9 @@ "posix" ], "cpu_cost": 1.0, - "exclude_configs": [], + "exclude_configs": [ + "msan" + ], "flaky": false, "language": "c", "name": "h2_sockpair_1byte_test", @@ -16622,7 +16678,9 @@ "posix" ], "cpu_cost": 1.0, - "exclude_configs": [], + "exclude_configs": [ + "msan" + ], "flaky": false, "language": "c", "name": "h2_sockpair_1byte_test", @@ -16643,7 +16701,9 @@ "posix" ], "cpu_cost": 0.1, - "exclude_configs": [], + "exclude_configs": [ + "msan" + ], "flaky": false, "language": "c", "name": "h2_sockpair_1byte_test", @@ -16664,7 +16724,9 @@ "posix" ], "cpu_cost": 1.0, - "exclude_configs": [], + "exclude_configs": [ + "msan" + ], "flaky": false, "language": "c", "name": "h2_sockpair_1byte_test", @@ -16685,7 +16747,9 @@ "posix" ], "cpu_cost": 1.0, - "exclude_configs": [], + "exclude_configs": [ + "msan" + ], "flaky": false, "language": "c", "name": "h2_sockpair_1byte_test", @@ -16706,7 +16770,9 @@ "posix" ], "cpu_cost": 1.0, - "exclude_configs": [], + "exclude_configs": [ + "msan" + ], "flaky": false, "language": "c", "name": "h2_sockpair_1byte_test", @@ -16727,7 +16793,9 @@ "posix" ], "cpu_cost": 1.0, - "exclude_configs": [], + "exclude_configs": [ + "msan" + ], "flaky": false, "language": "c", "name": "h2_sockpair_1byte_test", @@ -16748,7 +16816,9 @@ "posix" ], "cpu_cost": 1.0, - "exclude_configs": [], + "exclude_configs": [ + "msan" + ], "flaky": false, "language": "c", "name": "h2_sockpair_1byte_test", @@ -16769,7 +16839,9 @@ "posix" ], "cpu_cost": 1.0, - "exclude_configs": [], + "exclude_configs": [ + "msan" + ], "flaky": false, "language": "c", "name": "h2_sockpair_1byte_test", @@ -16790,7 +16862,9 @@ "posix" ], "cpu_cost": 1.0, - "exclude_configs": [], + "exclude_configs": [ + "msan" + ], "flaky": false, "language": "c", "name": "h2_sockpair_1byte_test", @@ -16811,7 +16885,9 @@ "posix" ], "cpu_cost": 1.0, - "exclude_configs": [], + "exclude_configs": [ + "msan" + ], "flaky": false, "language": "c", "name": "h2_sockpair_1byte_test", @@ -16832,7 +16908,9 @@ "posix" ], "cpu_cost": 1.0, - "exclude_configs": [], + "exclude_configs": [ + "msan" + ], "flaky": false, "language": "c", "name": "h2_sockpair_1byte_test", From 8f4e312c58a05c8fc595aa871d2c434ea1a3b87a Mon Sep 17 00:00:00 2001 From: Jorge Canizales Date: Wed, 19 Oct 2016 12:00:21 -0700 Subject: [PATCH 47/48] Update tests project to XCode 8 --- src/objective-c/tests/Info.plist | 2 +- .../tests/Tests.xcodeproj/project.pbxproj | 16 +++++++++++++--- .../xcshareddata/xcschemes/AllTests.xcscheme | 2 +- .../xcschemes/CoreCronetEnd2EndTests.xcscheme | 2 +- .../InteropTestsLocalCleartext.xcscheme | 2 +- .../xcschemes/InteropTestsLocalSSL.xcscheme | 2 +- .../xcschemes/InteropTestsRemote.xcscheme | 2 +- .../InteropTestsRemoteWithCronet.xcscheme | 2 +- .../xcschemes/RxLibraryUnitTests.xcscheme | 2 +- 9 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/objective-c/tests/Info.plist b/src/objective-c/tests/Info.plist index fbeeb96ba6c..ba72822e872 100644 --- a/src/objective-c/tests/Info.plist +++ b/src/objective-c/tests/Info.plist @@ -7,7 +7,7 @@ CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier - gRPC.$(PRODUCT_NAME:rfc1034identifier) + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/src/objective-c/tests/Tests.xcodeproj/project.pbxproj b/src/objective-c/tests/Tests.xcodeproj/project.pbxproj index c4a6567ae0e..8dccbf0f72b 100644 --- a/src/objective-c/tests/Tests.xcodeproj/project.pbxproj +++ b/src/objective-c/tests/Tests.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 48; objects = { /* Begin PBXBuildFile section */ @@ -535,7 +535,7 @@ 635697BF1B14FC11007A7283 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0630; + LastUpgradeCheck = 0800; ORGANIZATIONNAME = gRPC; TargetAttributes = { 5E8A5DA31D3840B4000F8BC4 = { @@ -565,7 +565,7 @@ }; }; buildConfigurationList = 635697C21B14FC11007A7283 /* Build configuration list for PBXProject "Tests" */; - compatibilityVersion = "Xcode 3.2"; + compatibilityVersion = "Xcode 8.0"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( @@ -1151,8 +1151,10 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; @@ -1205,6 +1207,7 @@ ); INFOPLIST_FILE = Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "gRPC.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Cronet; @@ -1362,6 +1365,7 @@ ); INFOPLIST_FILE = Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "gRPC.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; @@ -1376,6 +1380,7 @@ ); INFOPLIST_FILE = Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "gRPC.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; @@ -1393,13 +1398,16 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -1436,8 +1444,10 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; diff --git a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/AllTests.xcscheme b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/AllTests.xcscheme index d1d616c4cf2..740a1c0672d 100644 --- a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/AllTests.xcscheme +++ b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/AllTests.xcscheme @@ -1,6 +1,6 @@ Date: Wed, 19 Oct 2016 13:26:48 -0700 Subject: [PATCH 48/48] Avoid TSAN reported lock cycle --- test/core/iomgr/tcp_server_posix_test.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/core/iomgr/tcp_server_posix_test.c b/test/core/iomgr/tcp_server_posix_test.c index 6b1dd428a13..5791f562e11 100644 --- a/test/core/iomgr/tcp_server_posix_test.c +++ b/test/core/iomgr/tcp_server_posix_test.c @@ -118,8 +118,11 @@ static void on_connect(grpc_exec_ctx *exec_ctx, void *arg, grpc_endpoint *tcp, grpc_endpoint_shutdown(exec_ctx, tcp); grpc_endpoint_destroy(exec_ctx, tcp); + on_connect_result temp_result; + on_connect_result_set(&temp_result, acceptor); + gpr_mu_lock(g_mu); - on_connect_result_set(&g_result, acceptor); + g_result = temp_result; g_nconnects++; GPR_ASSERT( GRPC_LOG_IF_ERROR("pollset_kick", grpc_pollset_kick(g_pollset, NULL)));