Merge pull request #13246 from yashykt/testlinkage1
Remove grpc_slice_buf_cmp and change public_headers_must_be_c89 to pr…
diff --git a/src/core/ext/filters/client_channel/client_channel.cc b/src/core/ext/filters/client_channel/client_channel.cc
index 00c51ba..9eae6e0 100644
--- a/src/core/ext/filters/client_channel/client_channel.cc
+++ b/src/core/ext/filters/client_channel/client_channel.cc
@@ -88,7 +88,12 @@
}
}
-static void method_parameters_free(grpc_exec_ctx *exec_ctx, void *value) {
+// Wrappers to pass to grpc_service_config_create_method_config_table().
+static void *method_parameters_ref_wrapper(void *value) {
+ return method_parameters_ref((method_parameters *)value);
+}
+static void method_parameters_unref_wrapper(grpc_exec_ctx *exec_ctx,
+ void *value) {
method_parameters_unref((method_parameters *)value);
}
@@ -117,24 +122,16 @@
gpr_free(buf);
return false;
}
- // There should always be exactly 3, 6, or 9 fractional digits.
- int multiplier = 1;
- switch (strlen(decimal_point + 1)) {
- case 9:
- break;
- case 6:
- multiplier *= 1000;
- break;
- case 3:
- multiplier *= 1000000;
- break;
- default: // Unsupported number of digits.
- gpr_free(buf);
- return false;
+ int num_digits = (int)strlen(decimal_point + 1);
+ if (num_digits > 9) { // We don't accept greater precision than nanos.
+ gpr_free(buf);
+ return false;
}
- nanos *= multiplier;
+ for (int i = 0; i < (9 - num_digits); ++i) {
+ nanos *= 10;
+ }
}
- int seconds = gpr_parse_nonnegative_int(buf);
+ int seconds = decimal_point == buf ? 0 : gpr_parse_nonnegative_int(buf);
gpr_free(buf);
if (seconds == -1) return false;
*timeout = seconds * GPR_MS_PER_SEC + nanos / GPR_NS_PER_MS;
@@ -473,7 +470,7 @@
retry_throttle_data = parsing_state.retry_throttle_data;
method_params_table = grpc_service_config_create_method_config_table(
exec_ctx, service_config, method_parameters_create_from_json,
- method_parameters_free);
+ method_parameters_ref_wrapper, method_parameters_unref_wrapper);
grpc_service_config_destroy(service_config);
}
}
diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc
index 85e76e6..03116b4 100644
--- a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc
+++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc
@@ -1266,7 +1266,8 @@
} else if (!glb_policy->shutting_down) {
/* if we aren't shutting down, restart the LB client call after some time */
grpc_millis next_try =
- grpc_backoff_step(exec_ctx, &glb_policy->lb_call_backoff_state);
+ grpc_backoff_step(exec_ctx, &glb_policy->lb_call_backoff_state)
+ .next_attempt_start_time;
if (GRPC_TRACER_ON(grpc_lb_glb_trace)) {
gpr_log(GPR_DEBUG, "Connection to LB server lost (grpclb: %p)...",
(void *)glb_policy);
@@ -1431,7 +1432,7 @@
grpc_combiner_scheduler(glb_policy->base.combiner));
grpc_backoff_init(&glb_policy->lb_call_backoff_state,
- GRPC_GRPCLB_INITIAL_CONNECT_BACKOFF_SECONDS,
+ GRPC_GRPCLB_INITIAL_CONNECT_BACKOFF_SECONDS * 1000,
GRPC_GRPCLB_RECONNECT_BACKOFF_MULTIPLIER,
GRPC_GRPCLB_RECONNECT_JITTER,
GRPC_GRPCLB_MIN_CONNECT_TIMEOUT_SECONDS * 1000,
diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
index 5f7ab98..a1ddaee 100644
--- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
+++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
@@ -271,7 +271,8 @@
} else {
const char *msg = grpc_error_string(error);
gpr_log(GPR_DEBUG, "dns resolution failed: %s", msg);
- grpc_millis next_try = grpc_backoff_step(exec_ctx, &r->backoff_state);
+ grpc_millis next_try =
+ grpc_backoff_step(exec_ctx, &r->backoff_state).next_attempt_start_time;
grpc_millis timeout = next_try - grpc_exec_ctx_now(exec_ctx);
gpr_log(GPR_INFO, "dns resolution failed (will retry): %s",
grpc_error_string(error));
@@ -379,11 +380,11 @@
grpc_pollset_set_add_pollset_set(exec_ctx, r->interested_parties,
args->pollset_set);
}
- grpc_backoff_init(&r->backoff_state, GRPC_DNS_INITIAL_CONNECT_BACKOFF_SECONDS,
- GRPC_DNS_RECONNECT_BACKOFF_MULTIPLIER,
- GRPC_DNS_RECONNECT_JITTER,
- GRPC_DNS_MIN_CONNECT_TIMEOUT_SECONDS * 1000,
- GRPC_DNS_RECONNECT_MAX_BACKOFF_SECONDS * 1000);
+ grpc_backoff_init(
+ &r->backoff_state, GRPC_DNS_INITIAL_CONNECT_BACKOFF_SECONDS * 1000,
+ GRPC_DNS_RECONNECT_BACKOFF_MULTIPLIER, GRPC_DNS_RECONNECT_JITTER,
+ GRPC_DNS_MIN_CONNECT_TIMEOUT_SECONDS * 1000,
+ GRPC_DNS_RECONNECT_MAX_BACKOFF_SECONDS * 1000);
GRPC_CLOSURE_INIT(&r->dns_ares_on_retry_timer_locked,
dns_ares_on_retry_timer_locked, r,
grpc_combiner_scheduler(r->base.combiner));
diff --git a/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc b/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc
index e669b6d..62aead5 100644
--- a/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc
+++ b/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc
@@ -170,7 +170,8 @@
grpc_resolved_addresses_destroy(r->addresses);
grpc_lb_addresses_destroy(exec_ctx, addresses);
} else {
- grpc_millis next_try = grpc_backoff_step(exec_ctx, &r->backoff_state);
+ grpc_millis next_try =
+ grpc_backoff_step(exec_ctx, &r->backoff_state).next_attempt_start_time;
grpc_millis timeout = next_try - grpc_exec_ctx_now(exec_ctx);
gpr_log(GPR_INFO, "dns resolution failed (will retry): %s",
grpc_error_string(error));
@@ -256,11 +257,11 @@
grpc_pollset_set_add_pollset_set(exec_ctx, r->interested_parties,
args->pollset_set);
}
- grpc_backoff_init(&r->backoff_state, GRPC_DNS_INITIAL_CONNECT_BACKOFF_SECONDS,
- GRPC_DNS_RECONNECT_BACKOFF_MULTIPLIER,
- GRPC_DNS_RECONNECT_JITTER,
- GRPC_DNS_MIN_CONNECT_TIMEOUT_SECONDS * 1000,
- GRPC_DNS_RECONNECT_MAX_BACKOFF_SECONDS * 1000);
+ grpc_backoff_init(
+ &r->backoff_state, GRPC_DNS_INITIAL_CONNECT_BACKOFF_SECONDS * 1000,
+ GRPC_DNS_RECONNECT_BACKOFF_MULTIPLIER, GRPC_DNS_RECONNECT_JITTER,
+ GRPC_DNS_MIN_CONNECT_TIMEOUT_SECONDS * 1000,
+ GRPC_DNS_RECONNECT_MAX_BACKOFF_SECONDS * 1000);
return &r->base;
}
diff --git a/src/core/ext/filters/client_channel/subchannel.cc b/src/core/ext/filters/client_channel/subchannel.cc
index 5710a22..b954e1b 100644
--- a/src/core/ext/filters/client_channel/subchannel.cc
+++ b/src/core/ext/filters/client_channel/subchannel.cc
@@ -117,10 +117,10 @@
external_state_watcher root_external_state_watcher;
- /** next connect attempt time */
- grpc_millis next_attempt;
/** backoff state */
grpc_backoff backoff_state;
+ grpc_backoff_result backoff_result;
+
/** do we have an active alarm? */
bool have_alarm;
/** have we started the backoff loop */
@@ -380,7 +380,7 @@
grpc_connect_in_args args;
args.interested_parties = c->pollset_set;
- args.deadline = c->next_attempt;
+ args.deadline = c->backoff_result.current_deadline;
args.channel_args = c->args;
grpc_connectivity_state_set(exec_ctx, &c->state_tracker,
@@ -428,7 +428,7 @@
}
if (error == GRPC_ERROR_NONE) {
gpr_log(GPR_INFO, "Failed to connect to channel, retrying");
- c->next_attempt = grpc_backoff_step(exec_ctx, &c->backoff_state);
+ c->backoff_result = grpc_backoff_step(exec_ctx, &c->backoff_state);
continue_connect_locked(exec_ctx, c);
gpr_mu_unlock(&c->mu);
} else {
@@ -465,20 +465,21 @@
if (!c->backoff_begun) {
c->backoff_begun = true;
- c->next_attempt = grpc_backoff_begin(exec_ctx, &c->backoff_state);
+ c->backoff_result = grpc_backoff_begin(exec_ctx, &c->backoff_state);
continue_connect_locked(exec_ctx, c);
} else {
GPR_ASSERT(!c->have_alarm);
c->have_alarm = true;
const grpc_millis time_til_next =
- c->next_attempt - grpc_exec_ctx_now(exec_ctx);
+ c->backoff_result.next_attempt_start_time - grpc_exec_ctx_now(exec_ctx);
if (time_til_next <= 0) {
gpr_log(GPR_INFO, "Retry immediately");
} else {
gpr_log(GPR_INFO, "Retry in %" PRIdPTR " milliseconds", time_til_next);
}
GRPC_CLOSURE_INIT(&c->on_alarm, on_alarm, c, grpc_schedule_on_exec_ctx);
- grpc_timer_init(exec_ctx, &c->alarm, c->next_attempt, &c->on_alarm);
+ grpc_timer_init(exec_ctx, &c->alarm,
+ c->backoff_result.next_attempt_start_time, &c->on_alarm);
}
}
diff --git a/src/core/ext/filters/message_size/message_size_filter.cc b/src/core/ext/filters/message_size/message_size_filter.cc
index 5dc131b..9376d97 100644
--- a/src/core/ext/filters/message_size/message_size_filter.cc
+++ b/src/core/ext/filters/message_size/message_size_filter.cc
@@ -30,16 +30,34 @@
#include "src/core/lib/surface/channel_init.h"
#include "src/core/lib/transport/service_config.h"
-typedef struct message_size_limits {
+typedef struct {
int max_send_size;
int max_recv_size;
} message_size_limits;
-static void message_size_limits_free(grpc_exec_ctx* exec_ctx, void* value) {
- gpr_free(value);
+typedef struct {
+ gpr_refcount refs;
+ message_size_limits limits;
+} refcounted_message_size_limits;
+
+static void* refcounted_message_size_limits_ref(void* value) {
+ refcounted_message_size_limits* limits =
+ (refcounted_message_size_limits*)value;
+ gpr_ref(&limits->refs);
+ return value;
}
-static void* message_size_limits_create_from_json(const grpc_json* json) {
+static void refcounted_message_size_limits_unref(grpc_exec_ctx* exec_ctx,
+ void* value) {
+ refcounted_message_size_limits* limits =
+ (refcounted_message_size_limits*)value;
+ if (gpr_unref(&limits->refs)) {
+ gpr_free(value);
+ }
+}
+
+static void* refcounted_message_size_limits_create_from_json(
+ const grpc_json* json) {
int max_request_message_bytes = -1;
int max_response_message_bytes = -1;
for (grpc_json* field = json->child; field != NULL; field = field->next) {
@@ -60,10 +78,12 @@
if (max_response_message_bytes == -1) return NULL;
}
}
- message_size_limits* value =
- (message_size_limits*)gpr_malloc(sizeof(message_size_limits));
- value->max_send_size = max_request_message_bytes;
- value->max_recv_size = max_response_message_bytes;
+ refcounted_message_size_limits* value =
+ (refcounted_message_size_limits*)gpr_malloc(
+ sizeof(refcounted_message_size_limits));
+ gpr_ref_init(&value->refs, 1);
+ value->limits.max_send_size = max_request_message_bytes;
+ value->limits.max_recv_size = max_response_message_bytes;
return value;
}
@@ -82,7 +102,7 @@
typedef struct channel_data {
message_size_limits limits;
- // Maps path names to message_size_limits structs.
+ // Maps path names to refcounted_message_size_limits structs.
grpc_slice_hash_table* method_limit_table;
} channel_data;
@@ -164,19 +184,19 @@
// size to the receive limit.
calld->limits = chand->limits;
if (chand->method_limit_table != NULL) {
- message_size_limits* limits =
- (message_size_limits*)grpc_method_config_table_get(
+ refcounted_message_size_limits* limits =
+ (refcounted_message_size_limits*)grpc_method_config_table_get(
exec_ctx, chand->method_limit_table, args->path);
if (limits != NULL) {
- if (limits->max_send_size >= 0 &&
- (limits->max_send_size < calld->limits.max_send_size ||
+ if (limits->limits.max_send_size >= 0 &&
+ (limits->limits.max_send_size < calld->limits.max_send_size ||
calld->limits.max_send_size < 0)) {
- calld->limits.max_send_size = limits->max_send_size;
+ calld->limits.max_send_size = limits->limits.max_send_size;
}
- if (limits->max_recv_size >= 0 &&
- (limits->max_recv_size < calld->limits.max_recv_size ||
+ if (limits->limits.max_recv_size >= 0 &&
+ (limits->limits.max_recv_size < calld->limits.max_recv_size ||
calld->limits.max_recv_size < 0)) {
- calld->limits.max_recv_size = limits->max_recv_size;
+ calld->limits.max_recv_size = limits->limits.max_recv_size;
}
}
}
@@ -237,8 +257,10 @@
if (service_config != NULL) {
chand->method_limit_table =
grpc_service_config_create_method_config_table(
- exec_ctx, service_config, message_size_limits_create_from_json,
- message_size_limits_free);
+ exec_ctx, service_config,
+ refcounted_message_size_limits_create_from_json,
+ refcounted_message_size_limits_ref,
+ refcounted_message_size_limits_unref);
grpc_service_config_destroy(service_config);
}
}
diff --git a/src/core/lib/backoff/backoff.cc b/src/core/lib/backoff/backoff.cc
index fe0a751..5dd91da 100644
--- a/src/core/lib/backoff/backoff.cc
+++ b/src/core/lib/backoff/backoff.cc
@@ -20,23 +20,27 @@
#include <grpc/support/useful.h>
-void grpc_backoff_init(grpc_backoff *backoff,
- grpc_millis initial_connect_timeout, double multiplier,
- double jitter, grpc_millis min_timeout_millis,
- grpc_millis max_timeout_millis) {
- backoff->initial_connect_timeout = initial_connect_timeout;
+void grpc_backoff_init(grpc_backoff *backoff, grpc_millis initial_backoff,
+ double multiplier, double jitter,
+ grpc_millis min_connect_timeout,
+ grpc_millis max_backoff) {
+ backoff->initial_backoff = initial_backoff;
backoff->multiplier = multiplier;
backoff->jitter = jitter;
- backoff->min_timeout_millis = min_timeout_millis;
- backoff->max_timeout_millis = max_timeout_millis;
+ backoff->min_connect_timeout = min_connect_timeout;
+ backoff->max_backoff = max_backoff;
backoff->rng_state = (uint32_t)gpr_now(GPR_CLOCK_REALTIME).tv_nsec;
}
-grpc_millis grpc_backoff_begin(grpc_exec_ctx *exec_ctx, grpc_backoff *backoff) {
- backoff->current_timeout_millis = backoff->initial_connect_timeout;
- const grpc_millis first_timeout =
- GPR_MAX(backoff->current_timeout_millis, backoff->min_timeout_millis);
- return grpc_exec_ctx_now(exec_ctx) + first_timeout;
+grpc_backoff_result grpc_backoff_begin(grpc_exec_ctx *exec_ctx,
+ grpc_backoff *backoff) {
+ backoff->current_backoff = backoff->initial_backoff;
+ const grpc_millis initial_timeout =
+ GPR_MAX(backoff->initial_backoff, backoff->min_connect_timeout);
+ const grpc_millis now = grpc_exec_ctx_now(exec_ctx);
+ const grpc_backoff_result result = {now + initial_timeout,
+ now + backoff->current_backoff};
+ return result;
}
/* Generate a random number between 0 and 1. */
@@ -45,29 +49,32 @@
return *rng_state / (double)((uint32_t)1 << 31);
}
-grpc_millis grpc_backoff_step(grpc_exec_ctx *exec_ctx, grpc_backoff *backoff) {
- const double new_timeout_millis =
- backoff->multiplier * (double)backoff->current_timeout_millis;
- backoff->current_timeout_millis =
- GPR_MIN((grpc_millis)new_timeout_millis, backoff->max_timeout_millis);
+static double generate_uniform_random_number_between(uint32_t *rng_state,
+ double a, double b) {
+ if (a == b) return a;
+ if (a > b) GPR_SWAP(double, a, b); // make sure a < b
+ const double range = b - a;
+ return a + generate_uniform_random_number(rng_state) * range;
+}
- const double jitter_range_width = backoff->jitter * new_timeout_millis;
- const double jitter =
- (2 * generate_uniform_random_number(&backoff->rng_state) - 1) *
- jitter_range_width;
-
- backoff->current_timeout_millis =
- (grpc_millis)((double)(backoff->current_timeout_millis) + jitter);
-
- const grpc_millis current_deadline =
- grpc_exec_ctx_now(exec_ctx) + backoff->current_timeout_millis;
-
- const grpc_millis min_deadline =
- grpc_exec_ctx_now(exec_ctx) + backoff->min_timeout_millis;
-
- return GPR_MAX(current_deadline, min_deadline);
+grpc_backoff_result grpc_backoff_step(grpc_exec_ctx *exec_ctx,
+ grpc_backoff *backoff) {
+ backoff->current_backoff = (grpc_millis)(GPR_MIN(
+ backoff->current_backoff * backoff->multiplier, backoff->max_backoff));
+ const double jitter = generate_uniform_random_number_between(
+ &backoff->rng_state, -backoff->jitter * backoff->current_backoff,
+ backoff->jitter * backoff->current_backoff);
+ const grpc_millis current_timeout =
+ GPR_MAX((grpc_millis)(backoff->current_backoff + jitter),
+ backoff->min_connect_timeout);
+ const grpc_millis next_timeout = GPR_MIN(
+ (grpc_millis)(backoff->current_backoff + jitter), backoff->max_backoff);
+ const grpc_millis now = grpc_exec_ctx_now(exec_ctx);
+ const grpc_backoff_result result = {now + current_timeout,
+ now + next_timeout};
+ return result;
}
void grpc_backoff_reset(grpc_backoff *backoff) {
- backoff->current_timeout_millis = backoff->initial_connect_timeout;
+ backoff->current_backoff = backoff->initial_backoff;
}
diff --git a/src/core/lib/backoff/backoff.h b/src/core/lib/backoff/backoff.h
index 80e49ea..8becf4a 100644
--- a/src/core/lib/backoff/backoff.h
+++ b/src/core/lib/backoff/backoff.h
@@ -27,36 +27,53 @@
typedef struct {
/// const: how long to wait after the first failure before retrying
- grpc_millis initial_connect_timeout;
+ grpc_millis initial_backoff;
+
/// const: factor with which to multiply backoff after a failed retry
double multiplier;
+
/// const: amount to randomize backoffs
double jitter;
- /// const: minimum time between retries in milliseconds
- grpc_millis min_timeout_millis;
- /// const: maximum time between retries in milliseconds
- grpc_millis max_timeout_millis;
+
+ /// const: minimum time between retries
+ grpc_millis min_connect_timeout;
+
+ /// const: maximum time between retries
+ grpc_millis max_backoff;
+
+ /// current delay before retries
+ grpc_millis current_backoff;
/// random number generator
uint32_t rng_state;
-
- /// current retry timeout in milliseconds
- grpc_millis current_timeout_millis;
} grpc_backoff;
-/// Initialize backoff machinery - does not need to be destroyed
-void grpc_backoff_init(grpc_backoff *backoff,
- grpc_millis initial_connect_timeout, double multiplier,
- double jitter, grpc_millis min_timeout_millis,
- grpc_millis max_timeout_millis);
+typedef struct {
+ /// Deadline to be used for the current attempt.
+ grpc_millis current_deadline;
-/// Begin retry loop: returns a timespec for the NEXT retry
-grpc_millis grpc_backoff_begin(grpc_exec_ctx *exec_ctx, grpc_backoff *backoff);
-/// Step a retry loop: returns a timespec for the NEXT retry
-grpc_millis grpc_backoff_step(grpc_exec_ctx *exec_ctx, grpc_backoff *backoff);
+ /// Deadline to be used for the next attempt, following the backoff strategy.
+ grpc_millis next_attempt_start_time;
+} grpc_backoff_result;
+
+/// Initialize backoff machinery - does not need to be destroyed
+void grpc_backoff_init(grpc_backoff *backoff, grpc_millis initial_backoff,
+ double multiplier, double jitter,
+ grpc_millis min_connect_timeout,
+ grpc_millis max_backoff);
+
+/// Begin retry loop: returns the deadlines to be used for the current attempt
+/// and the subsequent retry, if any.
+grpc_backoff_result grpc_backoff_begin(grpc_exec_ctx *exec_ctx,
+ grpc_backoff *backoff);
+
+/// Step a retry loop: returns the deadlines to be used for the current attempt
+/// and the subsequent retry, if any.
+grpc_backoff_result grpc_backoff_step(grpc_exec_ctx *exec_ctx,
+ grpc_backoff *backoff);
+
/// Reset the backoff, so the next grpc_backoff_step will be a
-/// grpc_backoff_begin
-/// instead
+/// grpc_backoff_begin.
void grpc_backoff_reset(grpc_backoff *backoff);
#ifdef __cplusplus
diff --git a/src/core/lib/iomgr/pollset_windows.cc b/src/core/lib/iomgr/pollset_windows.cc
index bb4df83..01aff02 100644
--- a/src/core/lib/iomgr/pollset_windows.cc
+++ b/src/core/lib/iomgr/pollset_windows.cc
@@ -161,8 +161,10 @@
while (!worker.kicked) {
if (gpr_cv_wait(&worker.cv, &grpc_polling_mu,
grpc_millis_to_timespec(deadline, GPR_CLOCK_REALTIME))) {
+ grpc_exec_ctx_invalidate_now(exec_ctx);
break;
}
+ grpc_exec_ctx_invalidate_now(exec_ctx);
}
} else {
pollset->kicked_without_pollers = 0;
diff --git a/src/core/lib/transport/service_config.cc b/src/core/lib/transport/service_config.cc
index 070a13a..05907de 100644
--- a/src/core/lib/transport/service_config.cc
+++ b/src/core/lib/transport/service_config.cc
@@ -111,7 +111,13 @@
static size_t count_names_in_method_config_json(grpc_json* json) {
size_t num_names = 0;
for (grpc_json* field = json->child; field != NULL; field = field->next) {
- if (field->key != NULL && strcmp(field->key, "name") == 0) ++num_names;
+ if (field->key != NULL && strcmp(field->key, "name") == 0) {
+ if (field->type != GRPC_JSON_ARRAY) return -1;
+ for (grpc_json* name = field->child; name != NULL; name = name->next) {
+ if (name->type != GRPC_JSON_OBJECT) return -1;
+ ++num_names;
+ }
+ }
}
return num_names;
}
@@ -148,6 +154,8 @@
static bool parse_json_method_config(
grpc_exec_ctx* exec_ctx, grpc_json* json,
void* (*create_value)(const grpc_json* method_config_json),
+ void* (*ref_value)(void* value),
+ void (*unref_value)(grpc_exec_ctx* exec_ctx, void* value),
grpc_slice_hash_table_entry* entries, size_t* idx) {
// Construct value.
void* method_config = create_value(json);
@@ -162,6 +170,7 @@
if (child->type != GRPC_JSON_ARRAY) goto done;
for (grpc_json* name = child->child; name != NULL; name = name->next) {
char* path = parse_json_method_name(name);
+ if (path == NULL) goto done;
gpr_strvec_add(&paths, path);
}
}
@@ -170,11 +179,12 @@
// Add entry for each path.
for (size_t i = 0; i < paths.count; ++i) {
entries[*idx].key = grpc_slice_from_copied_string(paths.strs[i]);
- entries[*idx].value = method_config;
+ entries[*idx].value = ref_value(method_config);
++*idx;
}
success = true;
done:
+ unref_value(exec_ctx, method_config);
gpr_strvec_destroy(&paths);
return success;
}
@@ -182,7 +192,8 @@
grpc_slice_hash_table* grpc_service_config_create_method_config_table(
grpc_exec_ctx* exec_ctx, const grpc_service_config* service_config,
void* (*create_value)(const grpc_json* method_config_json),
- void (*destroy_value)(grpc_exec_ctx* exec_ctx, void* value)) {
+ void* (*ref_value)(void* value),
+ void (*unref_value)(grpc_exec_ctx* exec_ctx, void* value)) {
const grpc_json* json = service_config->json_tree;
// Traverse parsed JSON tree.
if (json->type != GRPC_JSON_OBJECT || json->key != NULL) return NULL;
@@ -196,7 +207,9 @@
// Find number of entries.
for (grpc_json* method = field->child; method != NULL;
method = method->next) {
- num_entries += count_names_in_method_config_json(method);
+ size_t count = count_names_in_method_config_json(method);
+ if (count <= 0) return NULL;
+ num_entries += count;
}
// Populate method config table entries.
entries = (grpc_slice_hash_table_entry*)gpr_malloc(
@@ -204,8 +217,13 @@
size_t idx = 0;
for (grpc_json* method = field->child; method != NULL;
method = method->next) {
- if (!parse_json_method_config(exec_ctx, method, create_value, entries,
- &idx)) {
+ if (!parse_json_method_config(exec_ctx, method, create_value, ref_value,
+ unref_value, entries, &idx)) {
+ for (size_t i = 0; i < idx; ++i) {
+ grpc_slice_unref_internal(exec_ctx, entries[i].key);
+ unref_value(exec_ctx, entries[i].value);
+ }
+ gpr_free(entries);
return NULL;
}
}
@@ -216,7 +234,7 @@
grpc_slice_hash_table* method_config_table = NULL;
if (entries != NULL) {
method_config_table =
- grpc_slice_hash_table_create(num_entries, entries, destroy_value, NULL);
+ grpc_slice_hash_table_create(num_entries, entries, unref_value, NULL);
gpr_free(entries);
}
return method_config_table;
diff --git a/src/core/lib/transport/service_config.h b/src/core/lib/transport/service_config.h
index 9c43093..405d0f5 100644
--- a/src/core/lib/transport/service_config.h
+++ b/src/core/lib/transport/service_config.h
@@ -46,12 +46,13 @@
/// Creates a method config table based on the data in \a json.
/// The table's keys are request paths. The table's value type is
/// returned by \a create_value(), based on data parsed from the JSON tree.
-/// \a destroy_value is used to clean up values.
+/// \a ref_value() and \a unref_value() are used to ref and unref values.
/// Returns NULL on error.
grpc_slice_hash_table* grpc_service_config_create_method_config_table(
grpc_exec_ctx* exec_ctx, const grpc_service_config* service_config,
void* (*create_value)(const grpc_json* method_config_json),
- void (*destroy_value)(grpc_exec_ctx* exec_ctx, void* value));
+ void* (*ref_value)(void* value),
+ void (*unref_value)(grpc_exec_ctx* exec_ctx, void* value));
/// A helper function for looking up values in the table returned by
/// \a grpc_service_config_create_method_config_table().
diff --git a/test/core/backoff/backoff_test.c b/test/core/backoff/backoff_test.c
index a29cce6..e80e0b3 100644
--- a/test/core/backoff/backoff_test.c
+++ b/test/core/backoff/backoff_test.c
@@ -19,120 +19,157 @@
#include "src/core/lib/backoff/backoff.h"
#include <grpc/support/log.h>
+#include <grpc/support/useful.h>
#include "test/core/util/test_config.h"
static void test_constant_backoff(void) {
grpc_backoff backoff;
- grpc_backoff_init(&backoff, 200 /* initial timeout */, 1.0 /* multiplier */,
- 0.0 /* jitter */, 100 /* min timeout */,
- 1000 /* max timeout */);
-
+ const grpc_millis initial_backoff = 200;
+ const double multiplier = 1.0;
+ const double jitter = 0.0;
+ const grpc_millis min_connect_timeout = 100;
+ const grpc_millis max_backoff = 1000;
+ grpc_backoff_init(&backoff, initial_backoff, multiplier, jitter,
+ min_connect_timeout, max_backoff);
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
- grpc_millis next = grpc_backoff_begin(&exec_ctx, &backoff);
- GPR_ASSERT(next - grpc_exec_ctx_now(&exec_ctx) == 200);
+ grpc_backoff_result next_deadlines = grpc_backoff_begin(&exec_ctx, &backoff);
+ GPR_ASSERT(next_deadlines.current_deadline - grpc_exec_ctx_now(&exec_ctx) ==
+ initial_backoff);
+ GPR_ASSERT(next_deadlines.next_attempt_start_time -
+ grpc_exec_ctx_now(&exec_ctx) ==
+ initial_backoff);
for (int i = 0; i < 10000; i++) {
- next = grpc_backoff_step(&exec_ctx, &backoff);
- GPR_ASSERT(next - grpc_exec_ctx_now(&exec_ctx) == 200);
- exec_ctx.now = next;
+ next_deadlines = grpc_backoff_step(&exec_ctx, &backoff);
+ GPR_ASSERT(next_deadlines.current_deadline - grpc_exec_ctx_now(&exec_ctx) ==
+ initial_backoff);
+ GPR_ASSERT(next_deadlines.next_attempt_start_time -
+ grpc_exec_ctx_now(&exec_ctx) ==
+ initial_backoff);
+ exec_ctx.now = next_deadlines.current_deadline;
}
grpc_exec_ctx_finish(&exec_ctx);
}
static void test_min_connect(void) {
grpc_backoff backoff;
- grpc_backoff_init(&backoff, 100 /* initial timeout */, 1.0 /* multiplier */,
- 0.0 /* jitter */, 200 /* min timeout */,
- 1000 /* max timeout */);
-
+ const grpc_millis initial_backoff = 100;
+ const double multiplier = 1.0;
+ const double jitter = 0.0;
+ const grpc_millis min_connect_timeout = 200;
+ const grpc_millis max_backoff = 1000;
+ grpc_backoff_init(&backoff, initial_backoff, multiplier, jitter,
+ min_connect_timeout, max_backoff);
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
- grpc_millis next = grpc_backoff_begin(&exec_ctx, &backoff);
- GPR_ASSERT(next - grpc_exec_ctx_now(&exec_ctx) == 200);
+ grpc_backoff_result next = grpc_backoff_begin(&exec_ctx, &backoff);
+ // Because the min_connect_timeout > initial_backoff, current_deadline is used
+ // as the deadline for the current attempt.
+ GPR_ASSERT(next.current_deadline - grpc_exec_ctx_now(&exec_ctx) ==
+ min_connect_timeout);
+ // ... while, if the current attempt fails, the next one will happen after
+ // initial_backoff.
+ GPR_ASSERT(next.next_attempt_start_time - grpc_exec_ctx_now(&exec_ctx) ==
+ initial_backoff);
grpc_exec_ctx_finish(&exec_ctx);
}
static void test_no_jitter_backoff(void) {
grpc_backoff backoff;
- grpc_backoff_init(&backoff, 2 /* initial timeout */, 2.0 /* multiplier */,
- 0.0 /* jitter */, 1 /* min timeout */,
- 513 /* max timeout */);
+ const grpc_millis initial_backoff = 2;
+ const double multiplier = 2.0;
+ const double jitter = 0.0;
+ const grpc_millis min_connect_timeout = 1;
+ const grpc_millis max_backoff = 513;
+ grpc_backoff_init(&backoff, initial_backoff, multiplier, jitter,
+ min_connect_timeout, max_backoff);
// x_1 = 2
// x_n = 2**i + x_{i-1} ( = 2**(n+1) - 2 )
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
exec_ctx.now = 0;
exec_ctx.now_is_valid = true;
- grpc_millis next = grpc_backoff_begin(&exec_ctx, &backoff);
- GPR_ASSERT(next == 2);
- exec_ctx.now = next;
- next = grpc_backoff_step(&exec_ctx, &backoff);
- GPR_ASSERT(next == 6);
- exec_ctx.now = next;
- next = grpc_backoff_step(&exec_ctx, &backoff);
- GPR_ASSERT(next == 14);
- exec_ctx.now = next;
- next = grpc_backoff_step(&exec_ctx, &backoff);
- GPR_ASSERT(next == 30);
- exec_ctx.now = next;
- next = grpc_backoff_step(&exec_ctx, &backoff);
- GPR_ASSERT(next == 62);
- exec_ctx.now = next;
- next = grpc_backoff_step(&exec_ctx, &backoff);
- GPR_ASSERT(next == 126);
- exec_ctx.now = next;
- next = grpc_backoff_step(&exec_ctx, &backoff);
- GPR_ASSERT(next == 254);
- exec_ctx.now = next;
- next = grpc_backoff_step(&exec_ctx, &backoff);
- GPR_ASSERT(next == 510);
- exec_ctx.now = next;
- next = grpc_backoff_step(&exec_ctx, &backoff);
- GPR_ASSERT(next == 1022);
- exec_ctx.now = next;
- next = grpc_backoff_step(&exec_ctx, &backoff);
+ grpc_backoff_result next_deadlines = grpc_backoff_begin(&exec_ctx, &backoff);
+ GPR_ASSERT(next_deadlines.current_deadline ==
+ next_deadlines.next_attempt_start_time);
+ GPR_ASSERT(next_deadlines.current_deadline == 2);
+ exec_ctx.now = next_deadlines.current_deadline;
+ next_deadlines = grpc_backoff_step(&exec_ctx, &backoff);
+ GPR_ASSERT(next_deadlines.current_deadline == 6);
+ exec_ctx.now = next_deadlines.current_deadline;
+ next_deadlines = grpc_backoff_step(&exec_ctx, &backoff);
+ GPR_ASSERT(next_deadlines.current_deadline == 14);
+ exec_ctx.now = next_deadlines.current_deadline;
+ next_deadlines = grpc_backoff_step(&exec_ctx, &backoff);
+ GPR_ASSERT(next_deadlines.current_deadline == 30);
+ exec_ctx.now = next_deadlines.current_deadline;
+ next_deadlines = grpc_backoff_step(&exec_ctx, &backoff);
+ GPR_ASSERT(next_deadlines.current_deadline == 62);
+ exec_ctx.now = next_deadlines.current_deadline;
+ next_deadlines = grpc_backoff_step(&exec_ctx, &backoff);
+ GPR_ASSERT(next_deadlines.current_deadline == 126);
+ exec_ctx.now = next_deadlines.current_deadline;
+ next_deadlines = grpc_backoff_step(&exec_ctx, &backoff);
+ GPR_ASSERT(next_deadlines.current_deadline == 254);
+ exec_ctx.now = next_deadlines.current_deadline;
+ next_deadlines = grpc_backoff_step(&exec_ctx, &backoff);
+ GPR_ASSERT(next_deadlines.current_deadline == 510);
+ exec_ctx.now = next_deadlines.current_deadline;
+ next_deadlines = grpc_backoff_step(&exec_ctx, &backoff);
+ GPR_ASSERT(next_deadlines.current_deadline == 1022);
+ exec_ctx.now = next_deadlines.current_deadline;
+ next_deadlines = grpc_backoff_step(&exec_ctx, &backoff);
// Hit the maximum timeout. From this point onwards, retries will increase
// only by max timeout.
- GPR_ASSERT(next == 1535);
- exec_ctx.now = next;
- next = grpc_backoff_step(&exec_ctx, &backoff);
- GPR_ASSERT(next == 2048);
- exec_ctx.now = next;
- next = grpc_backoff_step(&exec_ctx, &backoff);
- GPR_ASSERT(next == 2561);
+ GPR_ASSERT(next_deadlines.current_deadline == 1535);
+ exec_ctx.now = next_deadlines.current_deadline;
+ next_deadlines = grpc_backoff_step(&exec_ctx, &backoff);
+ GPR_ASSERT(next_deadlines.current_deadline == 2048);
+ exec_ctx.now = next_deadlines.current_deadline;
+ next_deadlines = grpc_backoff_step(&exec_ctx, &backoff);
+ GPR_ASSERT(next_deadlines.current_deadline == 2561);
grpc_exec_ctx_finish(&exec_ctx);
}
static void test_jitter_backoff(void) {
- const int64_t initial_timeout = 500;
+ const grpc_millis initial_backoff = 500;
+ grpc_millis current_backoff = initial_backoff;
+ const grpc_millis max_backoff = 1000;
+ const grpc_millis min_connect_timeout = 100;
+ const double multiplier = 1.0;
const double jitter = 0.1;
grpc_backoff backoff;
- grpc_backoff_init(&backoff, (grpc_millis)initial_timeout,
- 1.0 /* multiplier */, jitter, 100 /* min timeout */,
- 1000 /* max timeout */);
+ grpc_backoff_init(&backoff, initial_backoff, multiplier, jitter,
+ min_connect_timeout, max_backoff);
backoff.rng_state = 0; // force consistent PRNG
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
- grpc_millis next = grpc_backoff_begin(&exec_ctx, &backoff);
- GPR_ASSERT(next - grpc_exec_ctx_now(&exec_ctx) == 500);
+ grpc_backoff_result next_deadlines = grpc_backoff_begin(&exec_ctx, &backoff);
+ GPR_ASSERT(next_deadlines.current_deadline - grpc_exec_ctx_now(&exec_ctx) ==
+ initial_backoff);
+ GPR_ASSERT(next_deadlines.next_attempt_start_time -
+ grpc_exec_ctx_now(&exec_ctx) ==
+ initial_backoff);
- int64_t expected_next_lower_bound =
- (int64_t)((double)initial_timeout * (1 - jitter));
- int64_t expected_next_upper_bound =
- (int64_t)((double)initial_timeout * (1 + jitter));
+ grpc_millis expected_next_lower_bound =
+ (grpc_millis)((double)current_backoff * (1 - jitter));
+ grpc_millis expected_next_upper_bound =
+ (grpc_millis)((double)current_backoff * (1 + jitter));
for (int i = 0; i < 10000; i++) {
- next = grpc_backoff_step(&exec_ctx, &backoff);
-
- // next-now must be within (jitter*100)% of the previous timeout.
- const int64_t timeout_millis = next - grpc_exec_ctx_now(&exec_ctx);
+ next_deadlines = grpc_backoff_step(&exec_ctx, &backoff);
+ // next-now must be within (jitter*100)% of the current backoff (which
+ // increases by * multiplier up to max_backoff).
+ const grpc_millis timeout_millis =
+ next_deadlines.current_deadline - grpc_exec_ctx_now(&exec_ctx);
GPR_ASSERT(timeout_millis >= expected_next_lower_bound);
GPR_ASSERT(timeout_millis <= expected_next_upper_bound);
-
+ current_backoff = GPR_MIN(
+ (grpc_millis)((double)current_backoff * multiplier), max_backoff);
expected_next_lower_bound =
- (int64_t)((double)timeout_millis * (1 - jitter));
+ (grpc_millis)((double)current_backoff * (1 - jitter));
expected_next_upper_bound =
- (int64_t)((double)timeout_millis * (1 + jitter));
- exec_ctx.now = next;
+ (grpc_millis)((double)current_backoff * (1 + jitter));
+ exec_ctx.now = next_deadlines.current_deadline;
}
grpc_exec_ctx_finish(&exec_ctx);
}
diff --git a/test/core/end2end/tests/cancel_after_accept.c b/test/core/end2end/tests/cancel_after_accept.c
index c3ac0c3..96262b1 100644
--- a/test/core/end2end/tests/cancel_after_accept.c
+++ b/test/core/end2end/tests/cancel_after_accept.c
@@ -130,7 +130,8 @@
"{\n"
" \"methodConfig\": [ {\n"
" \"name\": [\n"
- " { \"service\": \"service\", \"method\": \"method\" }\n"
+ " { \"service\": \"service\", \"method\": \"method\" },\n"
+ " { \"service\": \"unused\" }\n"
" ],\n"
" \"timeout\": \"5s\"\n"
" } ]\n"
diff --git a/test/core/end2end/tests/max_message_length.c b/test/core/end2end/tests/max_message_length.c
index 01eb8d3..8925de9 100644
--- a/test/core/end2end/tests/max_message_length.c
+++ b/test/core/end2end/tests/max_message_length.c
@@ -138,7 +138,8 @@
? "{\n"
" \"methodConfig\": [ {\n"
" \"name\": [\n"
- " { \"service\": \"service\", \"method\": \"method\" }\n"
+ " { \"service\": \"service\", \"method\": \"method\" },\n"
+ " { \"service\": \"unused\" }\n"
" ],\n"
" \"maxRequestMessageBytes\": \"5\"\n"
" } ]\n"
diff --git a/test/cpp/microbenchmarks/fullstack_streaming_ping_pong.h b/test/cpp/microbenchmarks/fullstack_streaming_ping_pong.h
index 06d18b8..6df044f 100644
--- a/test/cpp/microbenchmarks/fullstack_streaming_ping_pong.h
+++ b/test/cpp/microbenchmarks/fullstack_streaming_ping_pong.h
@@ -278,7 +278,7 @@
void* t;
bool ok;
- int expect_tags;
+ int need_tags;
// Send 'max_ping_pongs' number of ping pong messages
int ping_pong_cnt = 0;
@@ -289,7 +289,7 @@
request_rw->Write(send_request, tag(2)); // Start client send
}
- int await_tags = (1 << 2);
+ need_tags = (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5);
if (ping_pong_cnt == 0) {
// wait for the server call structure (call_hook, etc.) to be
@@ -301,8 +301,8 @@
// In some cases tag:2 comes before tag:0 (write tag comes out
// first), this while loop is to make sure get tag:0.
int i = (int)(intptr_t)t;
- GPR_ASSERT(await_tags & (1 << i));
- await_tags &= ~(1 << i);
+ GPR_ASSERT(need_tags & (1 << i));
+ need_tags &= ~(1 << i);
GPR_ASSERT(fixture->cq()->Next(&t, &ok));
}
}
@@ -310,11 +310,7 @@
response_rw.Read(&recv_request, tag(3)); // Start server recv
request_rw->Read(&recv_response, tag(4)); // Start client recv
- await_tags |= (1 << 3) | (1 << 4);
- expect_tags = await_tags;
- await_tags |= (1 << 5);
-
- while (await_tags != 0) {
+ while (need_tags) {
GPR_ASSERT(fixture->cq()->Next(&t, &ok));
GPR_ASSERT(ok);
int i = (int)(intptr_t)t;
@@ -325,39 +321,34 @@
if (write_and_finish == 1) {
response_rw.WriteAndFinish(send_response, WriteOptions(),
Status::OK, tag(5));
- expect_tags |= (1 << 5);
} else {
response_rw.WriteLast(send_response, WriteOptions(), tag(5));
- // WriteLast buffers the write, so it's possible neither server
- // write op nor client read op will finish inside the while
- // loop.
- await_tags &= ~(1 << 4);
- await_tags &= ~(1 << 5);
- expect_tags |= (1 << 5);
+ // WriteLast buffers the write, so neither server write op nor
+ // client read op will finish inside the while loop.
+ need_tags &= ~(1 << 4);
+ need_tags &= ~(1 << 5);
}
} else {
response_rw.Write(send_response, tag(5));
- expect_tags |= (1 << 5);
}
}
- GPR_ASSERT(expect_tags & (1 << i));
- expect_tags &= ~(1 << i);
- await_tags &= ~(1 << i);
+ GPR_ASSERT(need_tags & (1 << i));
+ need_tags &= ~(1 << i);
}
ping_pong_cnt++;
}
if (max_ping_pongs == 0) {
- expect_tags |= (1 << 6) | (1 << 7) | (1 << 8);
+ need_tags = (1 << 6) | (1 << 7) | (1 << 8);
} else {
if (write_and_finish == 1) {
- expect_tags |= (1 << 8);
+ need_tags = (1 << 8);
} else {
// server's buffered write and the client's read of the buffered write
// tags should come up.
- expect_tags |= (1 << 7) | (1 << 8);
+ need_tags = (1 << 4) | (1 << 5) | (1 << 7) | (1 << 8);
}
}
@@ -369,8 +360,8 @@
GPR_ASSERT(fixture->cq()->Next(&t, &ok));
while ((int)(intptr_t)t != 0) {
int i = (int)(intptr_t)t;
- GPR_ASSERT(expect_tags & (1 << i));
- expect_tags &= ~(1 << i);
+ GPR_ASSERT(need_tags & (1 << i));
+ need_tags &= ~(1 << i);
GPR_ASSERT(fixture->cq()->Next(&t, &ok));
}
response_rw.Finish(Status::OK, tag(7));
@@ -383,11 +374,11 @@
Status recv_status;
request_rw->Finish(&recv_status, tag(8));
- while (expect_tags) {
+ while (need_tags) {
GPR_ASSERT(fixture->cq()->Next(&t, &ok));
int i = (int)(intptr_t)t;
- GPR_ASSERT(expect_tags & (1 << i));
- expect_tags &= ~(1 << i);
+ GPR_ASSERT(need_tags & (1 << i));
+ need_tags &= ~(1 << i);
}
GPR_ASSERT(recv_status.ok());
diff --git a/tools/gce/create_windows_debug_worker.sh b/tools/gce/create_windows_debug_worker.sh
index b56c8d9..da8050b 100755
--- a/tools/gce/create_windows_debug_worker.sh
+++ b/tools/gce/create_windows_debug_worker.sh
@@ -32,6 +32,17 @@
fi
MACHINE_TYPE=n1-standard-8
+TMP_DISK_NAME="$INSTANCE_NAME-temp-disk"
+
+gcloud compute disks create $TMP_DISK_NAME \
+ --project="$CLOUD_PROJECT" \
+ --zone "$ZONE" \
+ --image-project google.com:kokoro \
+ --image empty-100g-image \
+ --type pd-ssd
+
+echo 'Created scratch disk, waiting for it to become available.'
+sleep 15
gcloud compute instances create $INSTANCE_NAME \
--project="$CLOUD_PROJECT" \
@@ -41,4 +52,5 @@
--image kokoro-win7build-v9-prod-debug \
--boot-disk-size 500 \
--boot-disk-type pd-ssd \
- --tags=allow-ssh
+ --tags=allow-ssh \
+ --disk auto-delete=yes,boot=no,name=$TMP_DISK_NAME
diff --git a/tools/internal_ci/windows/grpc_basictests_dbg.cfg b/tools/internal_ci/windows/grpc_basictests_dbg.cfg
new file mode 100644
index 0000000..28d53cd
--- /dev/null
+++ b/tools/internal_ci/windows/grpc_basictests_dbg.cfg
@@ -0,0 +1,30 @@
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Config file for the internal CI (in protobuf text format)
+
+# Location of the continuous shell script in repository.
+build_file: "grpc/tools/internal_ci/windows/grpc_run_tests_matrix.bat"
+timeout_mins: 240
+action {
+ define_artifacts {
+ regex: "**/*sponge_log.xml"
+ regex: "github/grpc/reports/**"
+ }
+}
+
+env_vars {
+ key: "RUN_TESTS_FLAGS"
+ value: "-f basictests windows dbg -j 1 --inner_jobs 8 --internal_ci --bq_result_table aggregate_results"
+}
diff --git a/tools/internal_ci/windows/grpc_basictests_opt.cfg b/tools/internal_ci/windows/grpc_basictests_opt.cfg
new file mode 100644
index 0000000..4b7a965
--- /dev/null
+++ b/tools/internal_ci/windows/grpc_basictests_opt.cfg
@@ -0,0 +1,30 @@
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Config file for the internal CI (in protobuf text format)
+
+# Location of the continuous shell script in repository.
+build_file: "grpc/tools/internal_ci/windows/grpc_run_tests_matrix.bat"
+timeout_mins: 240
+action {
+ define_artifacts {
+ regex: "**/*sponge_log.xml"
+ regex: "github/grpc/reports/**"
+ }
+}
+
+env_vars {
+ key: "RUN_TESTS_FLAGS"
+ value: "-f basictests windows opt -j 1 --inner_jobs 8 --internal_ci --bq_result_table aggregate_results"
+}