Merge branch 'master' of github.com:grpc/grpc into authority_header
diff --git a/examples/cpp/route_guide/route_guide_server.cc b/examples/cpp/route_guide/route_guide_server.cc
index 24a4184..5867c16 100644
--- a/examples/cpp/route_guide/route_guide_server.cc
+++ b/examples/cpp/route_guide/route_guide_server.cc
@@ -51,6 +51,7 @@
return num * 3.1415926 /180;
}
+// The formula is based on http://mathforum.org/library/drmath/view/51879.html
float GetDistance(const Point& start, const Point& end) {
const float kCoordFactor = 10000000.0;
float lat_1 = start.latitude() / kCoordFactor;
diff --git a/examples/csharp/route_guide/RouteGuide/RouteGuideUtil.cs b/examples/csharp/route_guide/RouteGuide/RouteGuideUtil.cs
index 66c4a94..f9af190 100644
--- a/examples/csharp/route_guide/RouteGuide/RouteGuideUtil.cs
+++ b/examples/csharp/route_guide/RouteGuide/RouteGuideUtil.cs
@@ -52,26 +52,23 @@
/// <summary>
/// Calculate the distance between two points using the "haversine" formula.
- /// This code was taken from http://www.movable-type.co.uk/scripts/latlong.html.
+ /// The formula is based on http://mathforum.org/library/drmath/view/51879.html
/// </summary>
/// <param name="start">the starting point</param>
/// <param name="end">the end point</param>
/// <returns>the distance between the points in meters</returns>
public static double GetDistance(this Point start, Point end)
{
- double lat1 = start.GetLatitude();
- double lat2 = end.GetLatitude();
- double lon1 = start.GetLongitude();
- double lon2 = end.GetLongitude();
- int r = 6371000; // metres
- double phi1 = ToRadians(lat1);
- double phi2 = ToRadians(lat2);
- double deltaPhi = ToRadians(lat2 - lat1);
- double deltaLambda = ToRadians(lon2 - lon1);
+ int r = 6371000; // earth radius in metres
+ double lat1 = ToRadians(start.GetLatitude());
+ double lat2 = ToRadians(end.GetLatitude());
+ double lon1 = ToRadians(start.GetLongitude());
+ double lon2 = ToRadians(end.GetLongitude());
+ double deltalat = lat2 - lat1;
+ double deltalon = lon2 - lon1;
- double a = Math.Sin(deltaPhi / 2) * Math.Sin(deltaPhi / 2) + Math.Cos(phi1) * Math.Cos(phi2) * Math.Sin(deltaLambda / 2) * Math.Sin(deltaLambda / 2);
+ double a = Math.Sin(deltalat / 2) * Math.Sin(deltalat / 2) + Math.Cos(lat1) * Math.Cos(lat2) * Math.Sin(deltalon / 2) * Math.Sin(deltalon / 2);
double c = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a));
-
return r * c;
}
diff --git a/examples/node/dynamic_codegen/route_guide/route_guide_server.js b/examples/node/dynamic_codegen/route_guide/route_guide_server.js
index ab537ff..f9028e8 100644
--- a/examples/node/dynamic_codegen/route_guide/route_guide_server.js
+++ b/examples/node/dynamic_codegen/route_guide/route_guide_server.js
@@ -103,7 +103,7 @@
/**
* Calculate the distance between two points using the "haversine" formula.
- * This code was taken from http://www.movable-type.co.uk/scripts/latlong.html.
+ * The formula is based on http://mathforum.org/library/drmath/view/51879.html.
* @param start The starting point
* @param end The end point
* @return The distance between the points in meters
@@ -112,21 +112,18 @@
function toRadians(num) {
return num * Math.PI / 180;
}
- var lat1 = start.latitude / COORD_FACTOR;
- var lat2 = end.latitude / COORD_FACTOR;
- var lon1 = start.longitude / COORD_FACTOR;
- var lon2 = end.longitude / COORD_FACTOR;
- var R = 6371000; // metres
- var φ1 = toRadians(lat1);
- var φ2 = toRadians(lat2);
- var Δφ = toRadians(lat2-lat1);
- var Δλ = toRadians(lon2-lon1);
+ var R = 6371000; // earth radius in metres
+ var lat1 = toRadians(start.latitude / COORD_FACTOR);
+ var lat2 = toRadians(end.latitude / COORD_FACTOR);
+ var lon1 = toRadians(start.longitude / COORD_FACTOR);
+ var lon2 = toRadians(end.longitude / COORD_FACTOR);
- var a = Math.sin(Δφ/2) * Math.sin(Δφ/2) +
- Math.cos(φ1) * Math.cos(φ2) *
- Math.sin(Δλ/2) * Math.sin(Δλ/2);
+ var deltalat = lat2-lat1;
+ var deltalon = lon2-lon1;
+ var a = Math.sin(deltalat/2) * Math.sin(deltalat/2) +
+ Math.cos(lat1) * Math.cos(lat2) *
+ Math.sin(dlon/2) * Math.sin(dlon/2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
-
return R * c;
}
diff --git a/examples/node/static_codegen/route_guide/route_guide_server.js b/examples/node/static_codegen/route_guide/route_guide_server.js
index ef00bbb..eecac62 100644
--- a/examples/node/static_codegen/route_guide/route_guide_server.js
+++ b/examples/node/static_codegen/route_guide/route_guide_server.js
@@ -102,7 +102,7 @@
/**
* Calculate the distance between two points using the "haversine" formula.
- * This code was taken from http://www.movable-type.co.uk/scripts/latlong.html.
+ * The formula is based on http://mathforum.org/library/drmath/view/51879.html.
* @param start The starting point
* @param end The end point
* @return The distance between the points in meters
@@ -111,21 +111,18 @@
function toRadians(num) {
return num * Math.PI / 180;
}
- var lat1 = start.getLatitude() / COORD_FACTOR;
- var lat2 = end.getLatitude() / COORD_FACTOR;
- var lon1 = start.getLongitude() / COORD_FACTOR;
- var lon2 = end.getLongitude() / COORD_FACTOR;
- var R = 6371000; // metres
- var φ1 = toRadians(lat1);
- var φ2 = toRadians(lat2);
- var Δφ = toRadians(lat2-lat1);
- var Δλ = toRadians(lon2-lon1);
+ var R = 6371000; // earth radius in metres
+ var lat1 = toRadians(start.getLatitude() / COORD_FACTOR);
+ var lat2 = toRadians(end.getLatitude() / COORD_FACTOR);
+ var lon1 = toRadians(start.getLongitude() / COORD_FACTOR);
+ var lon2 = toRadians(end.getLongitude() / COORD_FACTOR);
- var a = Math.sin(Δφ/2) * Math.sin(Δφ/2) +
- Math.cos(φ1) * Math.cos(φ2) *
- Math.sin(Δλ/2) * Math.sin(Δλ/2);
+ var deltalat = lat2-lat1;
+ var deltalon = lon2-lon1;
+ var a = Math.sin(deltalat/2) * Math.sin(deltalat/2) +
+ Math.cos(lat1) * Math.cos(lat2) *
+ Math.sin(deltalon/2) * Math.sin(deltalon/2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
-
return R * c;
}
diff --git a/examples/python/route_guide/route_guide_server.py b/examples/python/route_guide/route_guide_server.py
index f10008f..1969fdd 100644
--- a/examples/python/route_guide/route_guide_server.py
+++ b/examples/python/route_guide/route_guide_server.py
@@ -46,6 +46,7 @@
delta_lat_rad = math.radians(lat_2 - lat_1)
delta_lon_rad = math.radians(lon_2 - lon_1)
+ # Formula is based on http://mathforum.org/library/drmath/view/51879.html
a = (pow(math.sin(delta_lat_rad / 2), 2) +
(math.cos(lat_rad_1) * math.cos(lat_rad_2) * pow(
math.sin(delta_lon_rad / 2), 2)))
diff --git a/examples/ruby/route_guide/route_guide_server.rb b/examples/ruby/route_guide/route_guide_server.rb
index 8ea07a2..5eb268b 100755
--- a/examples/ruby/route_guide/route_guide_server.rb
+++ b/examples/ruby/route_guide/route_guide_server.rb
@@ -32,19 +32,18 @@
RADIUS = 637_100
# Determines the distance between two points.
+# The formula is based on http://mathforum.org/library/drmath/view/51879.html.
def calculate_distance(point_a, point_b)
to_radians = proc { |x| x * Math::PI / 180 }
- lat_a = point_a.latitude / COORD_FACTOR
- lat_b = point_b.latitude / COORD_FACTOR
- long_a = point_a.longitude / COORD_FACTOR
- long_b = point_b.longitude / COORD_FACTOR
- φ1 = to_radians.call(lat_a)
- φ2 = to_radians.call(lat_b)
- Δφ = to_radians.call(lat_a - lat_b)
- Δλ = to_radians.call(long_a - long_b)
- a = Math.sin(Δφ / 2)**2 +
- Math.cos(φ1) * Math.cos(φ2) +
- Math.sin(Δλ / 2)**2
+ lat_a = to_radians.call(point_a.latitude / COORD_FACTOR)
+ lat_b = to_radians.call(point_b.latitude / COORD_FACTOR)
+ lon_a = to_radians.call(point_a.longitude / COORD_FACTOR)
+ lon_b = to_radians.call(point_b.longitude / COORD_FACTOR)
+ delta_lat = lat_a - lat_b
+ delta_lon = lon_a - lon_b
+ a = Math.sin(delta_lat / 2)**2 +
+ Math.cos(lat_a) * Math.cos(lat_b) +
+ Math.sin(delta_lon / 2)**2
(2 * RADIUS * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a))).to_i
end
diff --git a/include/grpcpp/impl/codegen/call.h b/include/grpcpp/impl/codegen/call.h
index 3b0fd60..28cc4a9 100644
--- a/include/grpcpp/impl/codegen/call.h
+++ b/include/grpcpp/impl/codegen/call.h
@@ -656,21 +656,6 @@
grpc_call* call_;
};
-/// A CallOpSet that does not post completions to the completion queue.
-///
-/// Allows hiding some completions that the C core must generate from
-/// C++ users.
-template <class Op1 = CallNoOp<1>, class Op2 = CallNoOp<2>,
- class Op3 = CallNoOp<3>, class Op4 = CallNoOp<4>,
- class Op5 = CallNoOp<5>, class Op6 = CallNoOp<6>>
-class SneakyCallOpSet : public CallOpSet<Op1, Op2, Op3, Op4, Op5, Op6> {
- public:
- bool FinalizeResult(void** tag, bool* status) override {
- typedef CallOpSet<Op1, Op2, Op3, Op4, Op5, Op6> Base;
- return Base::FinalizeResult(tag, status) && false;
- }
-};
-
/// Straightforward wrapping of the C call object
class Call final {
public:
diff --git a/include/grpcpp/server.h b/include/grpcpp/server.h
index e88e796..81c3907 100644
--- a/include/grpcpp/server.h
+++ b/include/grpcpp/server.h
@@ -162,8 +162,8 @@
friend class ServerInitializer;
class SyncRequest;
- class AsyncRequest;
- class ShutdownRequest;
+ class UnimplementedAsyncRequest;
+ class UnimplementedAsyncResponse;
/// SyncRequestThreadManager is an implementation of ThreadManager. This class
/// is responsible for polling for incoming RPCs and calling the RPC handlers.
@@ -171,10 +171,6 @@
/// interface)
class SyncRequestThreadManager;
- class UnimplementedAsyncRequestContext;
- class UnimplementedAsyncRequest;
- class UnimplementedAsyncResponse;
-
/// Register a generic service. This call does not take ownership of the
/// service. The service must exist for the lifetime of the Server instance.
void RegisterAsyncGenericService(AsyncGenericService* service) override;
diff --git a/src/core/ext/filters/client_channel/client_channel.cc b/src/core/ext/filters/client_channel/client_channel.cc
index bf3911e..67dd3a1 100644
--- a/src/core/ext/filters/client_channel/client_channel.cc
+++ b/src/core/ext/filters/client_channel/client_channel.cc
@@ -303,11 +303,16 @@
chand->lb_policy->SetReresolutionClosureLocked(&args->closure);
}
+// TODO(roth): The logic in this function is very hard to follow. We
+// should refactor this so that it's easier to understand, perhaps as
+// part of changing the resolver API to more clearly differentiate
+// between transient failures and shutdown.
static void on_resolver_result_changed_locked(void* arg, grpc_error* error) {
channel_data* chand = static_cast<channel_data*>(arg);
if (grpc_client_channel_trace.enabled()) {
- gpr_log(GPR_DEBUG, "chand=%p: got resolver result: error=%s", chand,
- grpc_error_string(error));
+ gpr_log(GPR_DEBUG,
+ "chand=%p: got resolver result: resolver_result=%p error=%s", chand,
+ chand->resolver_result, grpc_error_string(error));
}
// Extract the following fields from the resolver result, if non-nullptr.
bool lb_policy_updated = false;
@@ -423,8 +428,6 @@
}
}
}
- grpc_channel_args_destroy(chand->resolver_result);
- chand->resolver_result = nullptr;
}
if (grpc_client_channel_trace.enabled()) {
gpr_log(GPR_DEBUG,
@@ -497,6 +500,8 @@
"Channel disconnected", &error, 1));
GRPC_CLOSURE_LIST_SCHED(&chand->waiting_for_resolver_result_closures);
GRPC_CHANNEL_STACK_UNREF(chand->owning_stack, "resolver");
+ grpc_channel_args_destroy(chand->resolver_result);
+ chand->resolver_result = nullptr;
} else { // Not shutting down.
grpc_connectivity_state state = GRPC_CHANNEL_TRANSIENT_FAILURE;
grpc_error* state_error =
@@ -515,11 +520,16 @@
chand->exit_idle_when_lb_policy_arrives = false;
}
watch_lb_policy_locked(chand, chand->lb_policy.get(), state);
+ } else if (chand->resolver_result == nullptr) {
+ // Transient failure.
+ GRPC_CLOSURE_LIST_SCHED(&chand->waiting_for_resolver_result_closures);
}
if (!lb_policy_updated) {
set_channel_connectivity_state_locked(
chand, state, GRPC_ERROR_REF(state_error), "new_lb+resolver");
}
+ grpc_channel_args_destroy(chand->resolver_result);
+ chand->resolver_result = nullptr;
chand->resolver->NextLocked(&chand->resolver_result,
&chand->on_resolver_result_changed);
GRPC_ERROR_UNREF(state_error);
@@ -2753,7 +2763,45 @@
chand, calld);
}
async_pick_done_locked(elem, GRPC_ERROR_REF(error));
- } else if (chand->lb_policy != nullptr) {
+ } else if (chand->resolver == nullptr) {
+ // Shutting down.
+ if (grpc_client_channel_trace.enabled()) {
+ gpr_log(GPR_DEBUG, "chand=%p calld=%p: resolver disconnected", chand,
+ calld);
+ }
+ async_pick_done_locked(
+ elem, GRPC_ERROR_CREATE_FROM_STATIC_STRING("Disconnected"));
+ } else if (chand->lb_policy == nullptr) {
+ // Transient resolver failure.
+ // If call has wait_for_ready=true, try again; otherwise, fail.
+ uint32_t send_initial_metadata_flags =
+ calld->seen_send_initial_metadata
+ ? calld->send_initial_metadata_flags
+ : calld->pending_batches[0]
+ .batch->payload->send_initial_metadata
+ .send_initial_metadata_flags;
+ if (send_initial_metadata_flags & GRPC_INITIAL_METADATA_WAIT_FOR_READY) {
+ if (grpc_client_channel_trace.enabled()) {
+ gpr_log(GPR_DEBUG,
+ "chand=%p calld=%p: resolver returned but no LB policy; "
+ "wait_for_ready=true; trying again",
+ chand, calld);
+ }
+ pick_after_resolver_result_start_locked(elem);
+ } else {
+ if (grpc_client_channel_trace.enabled()) {
+ gpr_log(GPR_DEBUG,
+ "chand=%p calld=%p: resolver returned but no LB policy; "
+ "wait_for_ready=false; failing",
+ chand, calld);
+ }
+ async_pick_done_locked(
+ elem,
+ grpc_error_set_int(
+ GRPC_ERROR_CREATE_FROM_STATIC_STRING("Name resolution failure"),
+ GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE));
+ }
+ } else {
if (grpc_client_channel_trace.enabled()) {
gpr_log(GPR_DEBUG, "chand=%p calld=%p: resolver returned, doing pick",
chand, calld);
@@ -2767,30 +2815,6 @@
async_pick_done_locked(elem, GRPC_ERROR_NONE);
}
}
- // TODO(roth): It should be impossible for chand->lb_policy to be nullptr
- // here, so the rest of this code should never actually be executed.
- // However, we have reports of a crash on iOS that triggers this case,
- // so we are temporarily adding this to restore branches that were
- // removed in https://github.com/grpc/grpc/pull/12297. Need to figure
- // out what is actually causing this to occur and then figure out the
- // right way to deal with it.
- else if (chand->resolver != nullptr) {
- // No LB policy, so try again.
- if (grpc_client_channel_trace.enabled()) {
- gpr_log(GPR_DEBUG,
- "chand=%p calld=%p: resolver returned but no LB policy, "
- "trying again",
- chand, calld);
- }
- pick_after_resolver_result_start_locked(elem);
- } else {
- if (grpc_client_channel_trace.enabled()) {
- gpr_log(GPR_DEBUG, "chand=%p calld=%p: resolver disconnected", chand,
- calld);
- }
- async_pick_done_locked(
- elem, GRPC_ERROR_CREATE_FROM_STATIC_STRING("Disconnected"));
- }
}
static void pick_after_resolver_result_start_locked(grpc_call_element* elem) {
diff --git a/src/core/ext/filters/client_channel/resolver.h b/src/core/ext/filters/client_channel/resolver.h
index 1685a6c..cdb5a20 100644
--- a/src/core/ext/filters/client_channel/resolver.h
+++ b/src/core/ext/filters/client_channel/resolver.h
@@ -53,8 +53,12 @@
/// Requests a callback when a new result becomes available.
/// When the new result is available, sets \a *result to the new result
/// and schedules \a on_complete for execution.
+ /// Upon transient failure, sets \a *result to nullptr and schedules
+ /// \a on_complete with no error.
/// If resolution is fatally broken, sets \a *result to nullptr and
/// schedules \a on_complete with an error.
+ /// TODO(roth): When we have time, improve the way this API represents
+ /// transient failure vs. shutdown.
///
/// Note that the client channel will almost always have a request
/// to \a NextLocked() pending. When it gets the callback, it will
diff --git a/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc b/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc
index 4d8958f..99a33f2 100644
--- a/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc
+++ b/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc
@@ -82,6 +82,8 @@
grpc_closure* next_completion_ = nullptr;
// target result address for next completion
grpc_channel_args** target_result_ = nullptr;
+ // if true, return failure
+ bool return_failure_ = false;
};
FakeResolver::FakeResolver(const ResolverArgs& args) : Resolver(args.combiner) {
@@ -121,12 +123,16 @@
}
void FakeResolver::MaybeFinishNextLocked() {
- if (next_completion_ != nullptr && next_results_ != nullptr) {
- *target_result_ = grpc_channel_args_union(next_results_, channel_args_);
+ if (next_completion_ != nullptr &&
+ (next_results_ != nullptr || return_failure_)) {
+ *target_result_ =
+ return_failure_ ? nullptr
+ : grpc_channel_args_union(next_results_, channel_args_);
grpc_channel_args_destroy(next_results_);
next_results_ = nullptr;
GRPC_CLOSURE_SCHED(next_completion_, GRPC_ERROR_NONE);
next_completion_ = nullptr;
+ return_failure_ = false;
}
}
@@ -197,6 +203,26 @@
GRPC_ERROR_NONE);
}
+void FakeResolverResponseGenerator::SetFailureLocked(void* arg,
+ grpc_error* error) {
+ SetResponseClosureArg* closure_arg = static_cast<SetResponseClosureArg*>(arg);
+ FakeResolver* resolver = closure_arg->generator->resolver_;
+ resolver->return_failure_ = true;
+ resolver->MaybeFinishNextLocked();
+ Delete(closure_arg);
+}
+
+void FakeResolverResponseGenerator::SetFailure() {
+ GPR_ASSERT(resolver_ != nullptr);
+ SetResponseClosureArg* closure_arg = New<SetResponseClosureArg>();
+ closure_arg->generator = this;
+ GRPC_CLOSURE_SCHED(
+ GRPC_CLOSURE_INIT(&closure_arg->set_response_closure, SetFailureLocked,
+ closure_arg,
+ grpc_combiner_scheduler(resolver_->combiner())),
+ GRPC_ERROR_NONE);
+}
+
namespace {
static void* response_generator_arg_copy(void* p) {
diff --git a/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h b/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h
index 858f358..e5175f9 100644
--- a/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h
+++ b/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h
@@ -56,6 +56,10 @@
// resolver will return the last value set via \a SetResponse().
void SetReresolutionResponse(grpc_channel_args* response);
+ // Tells the resolver to return a transient failure (signalled by
+ // returning a null result with no error).
+ void SetFailure();
+
// Returns a channel arg containing \a generator.
static grpc_arg MakeChannelArg(FakeResolverResponseGenerator* generator);
@@ -68,6 +72,7 @@
static void SetResponseLocked(void* arg, grpc_error* error);
static void SetReresolutionResponseLocked(void* arg, grpc_error* error);
+ static void SetFailureLocked(void* arg, grpc_error* error);
FakeResolver* resolver_ = nullptr; // Do not own.
};
diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc
index a4d616d..ab69cec 100644
--- a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc
+++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc
@@ -68,7 +68,7 @@
#define DEFAULT_MIN_SENT_PING_INTERVAL_WITHOUT_DATA_MS 300000 /* 5 minutes */
#define DEFAULT_MIN_RECV_PING_INTERVAL_WITHOUT_DATA_MS 300000 /* 5 minutes */
-#define DEFAULT_MAX_PINGS_BETWEEN_DATA 0 /* unlimited */
+#define DEFAULT_MAX_PINGS_BETWEEN_DATA 2
#define DEFAULT_MAX_PING_STRIKES 2
static int g_default_client_keepalive_time_ms =
@@ -2630,7 +2630,7 @@
grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(arg);
GRPC_CHTTP2_REF_TRANSPORT(t, "keepalive watchdog");
grpc_timer_init(&t->keepalive_watchdog_timer,
- grpc_core::ExecCtx::Get()->Now() + t->keepalive_time,
+ grpc_core::ExecCtx::Get()->Now() + t->keepalive_timeout,
&t->keepalive_watchdog_fired_locked);
}
diff --git a/src/core/ext/transport/chttp2/transport/parsing.cc b/src/core/ext/transport/chttp2/transport/parsing.cc
index 988380b..a10c9ad 100644
--- a/src/core/ext/transport/chttp2/transport/parsing.cc
+++ b/src/core/ext/transport/chttp2/transport/parsing.cc
@@ -373,8 +373,6 @@
/* t->parser = grpc_chttp2_data_parser_parse;*/
t->parser = grpc_chttp2_data_parser_parse;
t->parser_data = &s->data_parser;
- t->ping_state.pings_before_data_required =
- t->ping_policy.max_pings_without_data;
t->ping_state.last_ping_sent_time = GRPC_MILLIS_INF_PAST;
return GRPC_ERROR_NONE;
} else if (grpc_error_get_int(err, GRPC_ERROR_INT_STREAM_ID, nullptr)) {
@@ -547,8 +545,6 @@
(t->incoming_frame_flags & GRPC_CHTTP2_DATA_FLAG_END_STREAM) != 0;
}
- t->ping_state.pings_before_data_required =
- t->ping_policy.max_pings_without_data;
t->ping_state.last_ping_sent_time = GRPC_MILLIS_INF_PAST;
/* could be a new grpc_chttp2_stream or an existing grpc_chttp2_stream */
diff --git a/src/core/ext/transport/chttp2/transport/writing.cc b/src/core/ext/transport/chttp2/transport/writing.cc
index 7471d88..6f32397 100644
--- a/src/core/ext/transport/chttp2/transport/writing.cc
+++ b/src/core/ext/transport/chttp2/transport/writing.cc
@@ -224,7 +224,7 @@
grpc_slice_buffer_add(
&t_->outbuf, grpc_chttp2_window_update_create(0, transport_announce,
&throwaway_stats));
- ResetPingRecvClock();
+ ResetPingClock();
}
}
@@ -269,11 +269,13 @@
return s;
}
- void ResetPingRecvClock() {
+ void ResetPingClock() {
if (!t_->is_client) {
t_->ping_recv_state.last_ping_recv_time = GRPC_MILLIS_INF_PAST;
t_->ping_recv_state.ping_strikes = 0;
}
+ t_->ping_state.pings_before_data_required =
+ t_->ping_policy.max_pings_without_data;
}
void IncInitialMetadataWrites() { ++initial_metadata_writes_; }
@@ -435,7 +437,7 @@
};
grpc_chttp2_encode_header(&t_->hpack_compressor, nullptr, 0,
s_->send_initial_metadata, &hopt, &t_->outbuf);
- write_context_->ResetPingRecvClock();
+ write_context_->ResetPingClock();
write_context_->IncInitialMetadataWrites();
}
@@ -455,7 +457,7 @@
grpc_slice_buffer_add(
&t_->outbuf, grpc_chttp2_window_update_create(s_->id, stream_announce,
&s_->stats.outgoing));
- write_context_->ResetPingRecvClock();
+ write_context_->ResetPingClock();
write_context_->IncWindowUpdateWrites();
}
@@ -489,7 +491,7 @@
data_send_context.CompressMoreBytes();
}
}
- write_context_->ResetPingRecvClock();
+ write_context_->ResetPingClock();
if (data_send_context.is_last_frame()) {
SentLastFrame();
}
@@ -530,7 +532,7 @@
s_->send_trailing_metadata, &hopt, &t_->outbuf);
}
write_context_->IncTrailingMetadataWrites();
- write_context_->ResetPingRecvClock();
+ write_context_->ResetPingClock();
SentLastFrame();
write_context_->NoteScheduledResults();
diff --git a/src/cpp/server/server_cc.cc b/src/cpp/server/server_cc.cc
index 760aaa4..391ca44 100644
--- a/src/cpp/server/server_cc.cc
+++ b/src/cpp/server/server_cc.cc
@@ -45,6 +45,7 @@
#include "src/cpp/thread_manager/thread_manager.h"
namespace grpc {
+namespace {
class DefaultGlobalCallbacks final : public Server::GlobalCallbacks {
public:
@@ -53,16 +54,29 @@
void PostSynchronousRequest(ServerContext* context) override {}
};
-static std::shared_ptr<Server::GlobalCallbacks> g_callbacks = nullptr;
-static gpr_once g_once_init_callbacks = GPR_ONCE_INIT;
+std::shared_ptr<Server::GlobalCallbacks> g_callbacks = nullptr;
+gpr_once g_once_init_callbacks = GPR_ONCE_INIT;
-static void InitGlobalCallbacks() {
+void InitGlobalCallbacks() {
if (!g_callbacks) {
g_callbacks.reset(new DefaultGlobalCallbacks());
}
}
-class Server::UnimplementedAsyncRequestContext {
+class ShutdownTag : public internal::CompletionQueueTag {
+ public:
+ bool FinalizeResult(void** tag, bool* status) { return false; }
+};
+
+class DummyTag : public internal::CompletionQueueTag {
+ public:
+ bool FinalizeResult(void** tag, bool* status) {
+ *status = true;
+ return true;
+ }
+};
+
+class UnimplementedAsyncRequestContext {
protected:
UnimplementedAsyncRequestContext() : generic_stream_(&server_context_) {}
@@ -70,8 +84,14 @@
GenericServerAsyncReaderWriter generic_stream_;
};
+} // namespace
+
+/// Use private inheritance rather than composition only to establish order
+/// of construction, since the public base class should be constructed after the
+/// elements belonging to the private base class are constructed. This is not
+/// possible using true composition.
class Server::UnimplementedAsyncRequest final
- : public UnimplementedAsyncRequestContext,
+ : private UnimplementedAsyncRequestContext,
public GenericAsyncRequest {
public:
UnimplementedAsyncRequest(Server* server, ServerCompletionQueue* cq)
@@ -90,38 +110,27 @@
ServerCompletionQueue* const cq_;
};
-typedef internal::SneakyCallOpSet<internal::CallOpSendInitialMetadata,
- internal::CallOpServerSendStatus>
- UnimplementedAsyncResponseOp;
+/// UnimplementedAsyncResponse should not post user-visible completions to the
+/// C++ completion queue, but is generated as a CQ event by the core
class Server::UnimplementedAsyncResponse final
- : public UnimplementedAsyncResponseOp {
+ : public internal::CallOpSet<internal::CallOpSendInitialMetadata,
+ internal::CallOpServerSendStatus> {
public:
UnimplementedAsyncResponse(UnimplementedAsyncRequest* request);
~UnimplementedAsyncResponse() { delete request_; }
bool FinalizeResult(void** tag, bool* status) override {
- bool r = UnimplementedAsyncResponseOp::FinalizeResult(tag, status);
+ internal::CallOpSet<
+ internal::CallOpSendInitialMetadata,
+ internal::CallOpServerSendStatus>::FinalizeResult(tag, status);
delete this;
- return r;
+ return false;
}
private:
UnimplementedAsyncRequest* const request_;
};
-class ShutdownTag : public internal::CompletionQueueTag {
- public:
- bool FinalizeResult(void** tag, bool* status) { return false; }
-};
-
-class DummyTag : public internal::CompletionQueueTag {
- public:
- bool FinalizeResult(void** tag, bool* status) {
- *status = true;
- return true;
- }
-};
-
class Server::SyncRequest final : public internal::CompletionQueueTag {
public:
SyncRequest(internal::RpcServiceMethod* method, void* tag)
diff --git a/src/csharp/Grpc.Core/Channel.cs b/src/csharp/Grpc.Core/Channel.cs
index e7b30cd..abe19a6 100644
--- a/src/csharp/Grpc.Core/Channel.cs
+++ b/src/csharp/Grpc.Core/Channel.cs
@@ -160,8 +160,17 @@
var deadlineTimespec = deadline.HasValue ? Timespec.FromDateTime(deadline.Value) : Timespec.InfFuture;
lock (myLock)
{
- // pass "tcs" as "state" for WatchConnectivityStateHandler.
- handle.WatchConnectivityState(lastObservedState, deadlineTimespec, completionQueue, WatchConnectivityStateHandler, tcs);
+ if (handle.IsClosed)
+ {
+ // If channel has been already shutdown and handle was disposed, we would end up with
+ // an abandoned completion added to the completion registry. Instead, we make sure we fail early.
+ throw new ObjectDisposedException(nameof(handle), "Channel handle has already been disposed.");
+ }
+ else
+ {
+ // pass "tcs" as "state" for WatchConnectivityStateHandler.
+ handle.WatchConnectivityState(lastObservedState, deadlineTimespec, completionQueue, WatchConnectivityStateHandler, tcs);
+ }
}
return tcs.Task;
}
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx.pxi
index 0892215..2e02111 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx.pxi
@@ -30,9 +30,12 @@
tag, operations, self if retain_self else None)
batch_operation_tag.prepare()
cpython.Py_INCREF(batch_operation_tag)
- return grpc_call_start_batch(
+ cdef grpc_call_error error
+ with nogil:
+ error = grpc_call_start_batch(
self.c_call, batch_operation_tag.c_ops, batch_operation_tag.c_nops,
<cpython.PyObject *>batch_operation_tag, NULL)
+ return error
def start_client_batch(self, operations, tag):
# We don't reference this call in the operations tag because
diff --git a/src/ruby/ext/grpc/extconf.rb b/src/ruby/ext/grpc/extconf.rb
index c1a0c56..e8e87e4 100644
--- a/src/ruby/ext/grpc/extconf.rb
+++ b/src/ruby/ext/grpc/extconf.rb
@@ -94,7 +94,6 @@
$CFLAGS << ' -Wall '
$CFLAGS << ' -Wextra '
$CFLAGS << ' -pedantic '
-$CFLAGS << ' -Wno-format '
output = File.join('grpc', 'grpc_c')
puts 'Generating Makefile for ' + output
diff --git a/src/ruby/ext/grpc/rb_compression_options.c b/src/ruby/ext/grpc/rb_compression_options.c
index 7fdec2e..4ba6991 100644
--- a/src/ruby/ext/grpc/rb_compression_options.c
+++ b/src/ruby/ext/grpc/rb_compression_options.c
@@ -186,7 +186,7 @@
error_message_ruby_str =
rb_str_new(error_message_str, strlen(error_message_str));
gpr_free(error_message_str);
- rb_raise(rb_eNameError, StringValueCStr(error_message_ruby_str));
+ rb_raise(rb_eNameError, "%s", StringValueCStr(error_message_ruby_str));
}
grpc_slice_unref(name_slice);
diff --git a/templates/tools/dockerfile/test/cxx_alpine_x64/Dockerfile.template b/templates/tools/dockerfile/test/cxx_alpine_x64/Dockerfile.template
new file mode 100644
index 0000000..1bbfdfd
--- /dev/null
+++ b/templates/tools/dockerfile/test/cxx_alpine_x64/Dockerfile.template
@@ -0,0 +1,57 @@
+%YAML 1.2
+--- |
+ # Copyright 2015 gRPC authors.
+ #
+ # Licensed under the Apache License, Version 2.0 (the "License");
+ # you may not use this file except in compliance with the License.
+ # You may obtain a copy of the License at
+ #
+ # http://www.apache.org/licenses/LICENSE-2.0
+ #
+ # Unless required by applicable law or agreed to in writing, software
+ # distributed under the License is distributed on an "AS IS" BASIS,
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ # See the License for the specific language governing permissions and
+ # limitations under the License.
+
+ FROM alpine:3.5
+
+ # Install Git and basic packages.
+ RUN apk update && apk add ${'\\'}
+ autoconf ${'\\'}
+ automake ${'\\'}
+ bzip2 ${'\\'}
+ build-base ${'\\'}
+ cmake ${'\\'}
+ ccache ${'\\'}
+ curl ${'\\'}
+ gcc ${'\\'}
+ git ${'\\'}
+ libtool ${'\\'}
+ linux-headers ${'\\'}
+ make ${'\\'}
+ perl ${'\\'}
+ strace ${'\\'}
+ python-dev ${'\\'}
+ py-pip ${'\\'}
+ unzip ${'\\'}
+ wget ${'\\'}
+ zip
+
+ # Install Python packages from PyPI
+ RUN pip install --upgrade pip==9.0.1
+ RUN pip install virtualenv
+ RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
+
+ # Google Cloud platform API libraries
+ RUN pip install --upgrade google-api-python-client
+
+ # Install gflags
+ RUN git clone https://github.com/gflags/gflags.git && cd gflags && git checkout v2.2.0
+ RUN cd gflags && cmake . && make && make install
+ RUN ln -s /usr/local/include/gflags /usr/include/gflags
+
+ <%include file="../../run_tests_addons.include"/>
+
+ # Define the default command.
+ CMD ["bash"]
diff --git a/test/core/end2end/no_server_test.cc b/test/core/end2end/no_server_test.cc
index 6113885..e8ce403 100644
--- a/test/core/end2end/no_server_test.cc
+++ b/test/core/end2end/no_server_test.cc
@@ -22,45 +22,47 @@
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
+#include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h"
#include "test/core/end2end/cq_verifier.h"
#include "test/core/util/test_config.h"
static void* tag(intptr_t i) { return (void*)i; }
-int main(int argc, char** argv) {
- grpc_channel* chan;
- grpc_call* call;
- gpr_timespec deadline = grpc_timeout_seconds_to_deadline(2);
- grpc_completion_queue* cq;
- cq_verifier* cqv;
- grpc_op ops[6];
- grpc_op* op;
- grpc_metadata_array trailing_metadata_recv;
- grpc_status_code status;
- grpc_slice details;
+void run_test(bool wait_for_ready) {
+ gpr_log(GPR_INFO, "TEST: wait_for_ready=%d", wait_for_ready);
- grpc_test_init(argc, argv);
grpc_init();
- grpc_metadata_array_init(&trailing_metadata_recv);
+ grpc_completion_queue* cq = grpc_completion_queue_create_for_next(nullptr);
+ cq_verifier* cqv = cq_verifier_create(cq);
- cq = grpc_completion_queue_create_for_next(nullptr);
- cqv = cq_verifier_create(cq);
+ grpc_core::RefCountedPtr<grpc_core::FakeResolverResponseGenerator>
+ response_generator =
+ grpc_core::MakeRefCounted<grpc_core::FakeResolverResponseGenerator>();
+ grpc_arg arg = grpc_core::FakeResolverResponseGenerator::MakeChannelArg(
+ response_generator.get());
+ grpc_channel_args args = {1, &arg};
/* create a call, channel to a non existant server */
- chan = grpc_insecure_channel_create("nonexistant:54321", nullptr, nullptr);
- grpc_slice host = grpc_slice_from_static_string("nonexistant");
- call = grpc_channel_create_call(chan, nullptr, GRPC_PROPAGATE_DEFAULTS, cq,
- grpc_slice_from_static_string("/Foo"), &host,
- deadline, nullptr);
+ grpc_channel* chan =
+ grpc_insecure_channel_create("fake:nonexistant", &args, nullptr);
+ gpr_timespec deadline = grpc_timeout_seconds_to_deadline(2);
+ grpc_call* call = grpc_channel_create_call(
+ chan, nullptr, GRPC_PROPAGATE_DEFAULTS, cq,
+ grpc_slice_from_static_string("/Foo"), nullptr, deadline, nullptr);
+ grpc_op ops[6];
memset(ops, 0, sizeof(ops));
- op = ops;
+ grpc_op* op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
- op->flags = 0;
+ op->flags = wait_for_ready ? GRPC_INITIAL_METADATA_WAIT_FOR_READY : 0;
op->reserved = nullptr;
op++;
+ grpc_metadata_array trailing_metadata_recv;
+ grpc_metadata_array_init(&trailing_metadata_recv);
+ grpc_status_code status;
+ grpc_slice details;
op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
op->data.recv_status_on_client.status = &status;
@@ -71,11 +73,25 @@
GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(call, ops,
(size_t)(op - ops), tag(1),
nullptr));
+
+ {
+ grpc_core::ExecCtx exec_ctx;
+ response_generator->SetFailure();
+ }
+
/* verify that all tags get completed */
CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
cq_verify(cqv);
- GPR_ASSERT(status == GRPC_STATUS_DEADLINE_EXCEEDED);
+ gpr_log(GPR_INFO, "call status: %d", status);
+ if (wait_for_ready) {
+ GPR_ASSERT(status == GRPC_STATUS_DEADLINE_EXCEEDED);
+ } else {
+ GPR_ASSERT(status == GRPC_STATUS_UNAVAILABLE);
+ }
+
+ grpc_slice_unref(details);
+ grpc_metadata_array_destroy(&trailing_metadata_recv);
grpc_completion_queue_shutdown(cq);
while (grpc_completion_queue_next(cq, gpr_inf_future(GPR_CLOCK_REALTIME),
@@ -87,10 +103,12 @@
grpc_channel_destroy(chan);
cq_verifier_destroy(cqv);
- grpc_slice_unref(details);
- grpc_metadata_array_destroy(&trailing_metadata_recv);
-
grpc_shutdown();
+}
+int main(int argc, char** argv) {
+ grpc_test_init(argc, argv);
+ run_test(true /* wait_for_ready */);
+ run_test(false /* wait_for_ready */);
return 0;
}
diff --git a/test/core/end2end/tests/bad_ping.cc b/test/core/end2end/tests/bad_ping.cc
index 00edf63..b80b228 100644
--- a/test/core/end2end/tests/bad_ping.cc
+++ b/test/core/end2end/tests/bad_ping.cc
@@ -28,7 +28,7 @@
#include "src/core/lib/gpr/useful.h"
#include "test/core/end2end/cq_verifier.h"
-#define MAX_PING_STRIKES 1
+#define MAX_PING_STRIKES 2
static void* tag(intptr_t t) { return (void*)t; }
@@ -62,6 +62,7 @@
grpc_completion_queue_destroy(f->shutdown_cq);
}
+// Send more pings than server allows to trigger server's GOAWAY.
static void test_bad_ping(grpc_end2end_test_config config) {
grpc_end2end_test_fixture f = config.create_fixture(nullptr, nullptr);
cq_verifier* cqv = cq_verifier_create(f.cq);
@@ -217,9 +218,170 @@
config.tear_down_data(&f);
}
+// Try sending more pings than server allows, but server should be fine because
+// max_pings_without_data should limit pings sent out on wire.
+static void test_pings_without_data(grpc_end2end_test_config config) {
+ grpc_end2end_test_fixture f = config.create_fixture(nullptr, nullptr);
+ cq_verifier* cqv = cq_verifier_create(f.cq);
+ grpc_arg client_a[3];
+ client_a[0].type = GRPC_ARG_INTEGER;
+ client_a[0].key =
+ const_cast<char*>(GRPC_ARG_HTTP2_MIN_SENT_PING_INTERVAL_WITHOUT_DATA_MS);
+ client_a[0].value.integer = 10;
+ // Only allow MAX_PING_STRIKES pings without data (DATA/HEADERS/WINDOW_UPDATE)
+ // so that the transport will throttle the excess pings.
+ client_a[1].type = GRPC_ARG_INTEGER;
+ client_a[1].key = const_cast<char*>(GRPC_ARG_HTTP2_MAX_PINGS_WITHOUT_DATA);
+ client_a[1].value.integer = MAX_PING_STRIKES;
+ client_a[2].type = GRPC_ARG_INTEGER;
+ client_a[2].key = const_cast<char*>(GRPC_ARG_HTTP2_BDP_PROBE);
+ client_a[2].value.integer = 0;
+ grpc_arg server_a[3];
+ server_a[0].type = GRPC_ARG_INTEGER;
+ server_a[0].key =
+ const_cast<char*>(GRPC_ARG_HTTP2_MIN_RECV_PING_INTERVAL_WITHOUT_DATA_MS);
+ server_a[0].value.integer = 300000 /* 5 minutes */;
+ server_a[1].type = GRPC_ARG_INTEGER;
+ server_a[1].key = const_cast<char*>(GRPC_ARG_HTTP2_MAX_PING_STRIKES);
+ server_a[1].value.integer = MAX_PING_STRIKES;
+ server_a[2].type = GRPC_ARG_INTEGER;
+ server_a[2].key = const_cast<char*>(GRPC_ARG_HTTP2_BDP_PROBE);
+ server_a[2].value.integer = 0;
+ grpc_channel_args client_args = {GPR_ARRAY_SIZE(client_a), client_a};
+ grpc_channel_args server_args = {GPR_ARRAY_SIZE(server_a), server_a};
+
+ config.init_client(&f, &client_args);
+ config.init_server(&f, &server_args);
+
+ grpc_call* c;
+ grpc_call* s;
+ gpr_timespec deadline = grpc_timeout_seconds_to_deadline(10);
+ grpc_op ops[6];
+ grpc_op* op;
+ grpc_metadata_array initial_metadata_recv;
+ grpc_metadata_array trailing_metadata_recv;
+ grpc_metadata_array request_metadata_recv;
+ grpc_call_details call_details;
+ grpc_status_code status;
+ grpc_call_error error;
+ grpc_slice details;
+ int was_cancelled = 2;
+
+ c = grpc_channel_create_call(
+ f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq,
+ grpc_slice_from_static_string("/foo"),
+ get_host_override_slice("foo.test.google.fr:1234", config), deadline,
+ nullptr);
+ GPR_ASSERT(c);
+
+ grpc_metadata_array_init(&initial_metadata_recv);
+ grpc_metadata_array_init(&trailing_metadata_recv);
+ grpc_metadata_array_init(&request_metadata_recv);
+ grpc_call_details_init(&call_details);
+
+ memset(ops, 0, sizeof(ops));
+ op = ops;
+ op->op = GRPC_OP_SEND_INITIAL_METADATA;
+ op->data.send_initial_metadata.count = 0;
+ op->data.send_initial_metadata.metadata = nullptr;
+ op->flags = 0;
+ op->reserved = nullptr;
+ op++;
+ op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
+ op->flags = 0;
+ op->reserved = nullptr;
+ op++;
+ op->op = GRPC_OP_RECV_INITIAL_METADATA;
+ op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
+ op->flags = 0;
+ op->reserved = nullptr;
+ op++;
+ op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+ op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
+ op->data.recv_status_on_client.status = &status;
+ op->data.recv_status_on_client.status_details = &details;
+ op->flags = 0;
+ op->reserved = nullptr;
+ op++;
+ error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+ nullptr);
+ GPR_ASSERT(GRPC_CALL_OK == error);
+
+ error =
+ grpc_server_request_call(f.server, &s, &call_details,
+ &request_metadata_recv, f.cq, f.cq, tag(101));
+ GPR_ASSERT(GRPC_CALL_OK == error);
+ CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
+ cq_verify(cqv);
+
+ // Send too many pings to the server similar to the prevous test case.
+ // However, since we set the MAX_PINGS_WITHOUT_DATA at the client side, only
+ // MAX_PING_STRIKES will actually be sent and the rpc will still succeed.
+ int i;
+ for (i = 1; i <= MAX_PING_STRIKES + 2; i++) {
+ grpc_channel_ping(f.client, f.cq, tag(200 + i), nullptr);
+ if (i <= MAX_PING_STRIKES) {
+ CQ_EXPECT_COMPLETION(cqv, tag(200 + i), 1);
+ }
+ cq_verify(cqv);
+ }
+
+ memset(ops, 0, sizeof(ops));
+ op = ops;
+ op->op = GRPC_OP_SEND_INITIAL_METADATA;
+ op->data.send_initial_metadata.count = 0;
+ op->flags = 0;
+ op->reserved = nullptr;
+ op++;
+ op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+ op->data.send_status_from_server.trailing_metadata_count = 0;
+ op->data.send_status_from_server.status = GRPC_STATUS_UNIMPLEMENTED;
+ grpc_slice status_details = grpc_slice_from_static_string("xyz");
+ op->data.send_status_from_server.status_details = &status_details;
+ op->flags = 0;
+ op->reserved = nullptr;
+ op++;
+ op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
+ op->data.recv_close_on_server.cancelled = &was_cancelled;
+ op->flags = 0;
+ op->reserved = nullptr;
+ op++;
+ error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
+ nullptr);
+ GPR_ASSERT(GRPC_CALL_OK == error);
+
+ CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
+ // Client call should return.
+ CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
+ cq_verify(cqv);
+
+ grpc_server_shutdown_and_notify(f.server, f.cq, tag(0xdead));
+ CQ_EXPECT_COMPLETION(cqv, tag(0xdead), 1);
+ cq_verify(cqv);
+
+ grpc_call_unref(s);
+
+ // The rpc should be successful.
+ GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED);
+ GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/foo"));
+ validate_host_override_string("foo.test.google.fr:1234", call_details.host,
+ config);
+
+ grpc_slice_unref(details);
+ grpc_metadata_array_destroy(&initial_metadata_recv);
+ grpc_metadata_array_destroy(&trailing_metadata_recv);
+ grpc_metadata_array_destroy(&request_metadata_recv);
+ grpc_call_details_destroy(&call_details);
+ grpc_call_unref(c);
+ cq_verifier_destroy(cqv);
+ end_test(&f);
+ config.tear_down_data(&f);
+}
+
void bad_ping(grpc_end2end_test_config config) {
GPR_ASSERT(config.feature_mask & FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION);
test_bad_ping(config);
+ test_pings_without_data(config);
}
void bad_ping_pre_init(void) {}
diff --git a/test/core/end2end/tests/keepalive_timeout.cc b/test/core/end2end/tests/keepalive_timeout.cc
index 9168a4e..1ee5285 100644
--- a/test/core/end2end/tests/keepalive_timeout.cc
+++ b/test/core/end2end/tests/keepalive_timeout.cc
@@ -102,7 +102,7 @@
grpc_arg keepalive_arg_elems[3];
keepalive_arg_elems[0].type = GRPC_ARG_INTEGER;
keepalive_arg_elems[0].key = const_cast<char*>(GRPC_ARG_KEEPALIVE_TIME_MS);
- keepalive_arg_elems[0].value.integer = 1500;
+ keepalive_arg_elems[0].value.integer = 3500;
keepalive_arg_elems[1].type = GRPC_ARG_INTEGER;
keepalive_arg_elems[1].key = const_cast<char*>(GRPC_ARG_KEEPALIVE_TIMEOUT_MS);
keepalive_arg_elems[1].value.integer = 0;
diff --git a/test/distrib/php/run_distrib_test.sh b/test/distrib/php/run_distrib_test.sh
index a6102f6..ef2de4f 100755
--- a/test/distrib/php/run_distrib_test.sh
+++ b/test/distrib/php/run_distrib_test.sh
@@ -20,6 +20,6 @@
cp -r "$EXTERNAL_GIT_ROOT"/input_artifacts/grpc-*.tgz .
find . -regex ".*/grpc-[0-9].*.tgz" | cut -b3- | \
- xargs pecl install
+ xargs sudo pecl install
php -d extension=grpc.so -d max_execution_time=300 distribtest.php
diff --git a/tools/dockerfile/test/cxx_alpine_x64/Dockerfile b/tools/dockerfile/test/cxx_alpine_x64/Dockerfile
index 8e5403f..c68a5dd 100644
--- a/tools/dockerfile/test/cxx_alpine_x64/Dockerfile
+++ b/tools/dockerfile/test/cxx_alpine_x64/Dockerfile
@@ -39,23 +39,27 @@
# Install Python packages from PyPI
RUN pip install --upgrade pip==9.0.1
RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
# Google Cloud platform API libraries
RUN pip install --upgrade google-api-python-client
-# Prepare ccache
-RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
-RUN ln -s /usr/bin/ccache /usr/local/bin/g++
-RUN ln -s /usr/bin/ccache /usr/local/bin/cc
-RUN ln -s /usr/bin/ccache /usr/local/bin/c++
-
# Install gflags
RUN git clone https://github.com/gflags/gflags.git && cd gflags && git checkout v2.2.0
RUN cd gflags && cmake . && make && make install
RUN ln -s /usr/local/include/gflags /usr/include/gflags
-RUN mkdir -p /var/local/jenkins
+# Prepare ccache
+RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
+RUN ln -s /usr/bin/ccache /usr/local/bin/g++
+RUN ln -s /usr/bin/ccache /usr/local/bin/cc
+RUN ln -s /usr/bin/ccache /usr/local/bin/c++
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
+
+
+RUN mkdir /var/local/jenkins
+
# Define the default command.
CMD ["bash"]
diff --git a/tools/internal_ci/linux/grpc_android.cfg b/tools/internal_ci/linux/grpc_android.cfg
new file mode 100644
index 0000000..fb60777
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_android.cfg
@@ -0,0 +1,19 @@
+# Copyright 2018 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Config file for the internal CI (in protobuf text format)
+
+# Location of the continuous shell script in repository.
+build_file: "grpc/tools/internal_ci/linux/grpc_android.sh"
+timeout_mins: 60
diff --git a/tools/internal_ci/linux/grpc_android.sh b/tools/internal_ci/linux/grpc_android.sh
new file mode 100755
index 0000000..1417b96
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_android.sh
@@ -0,0 +1,30 @@
+#!/usr/bin/env bash
+# Copyright 2018 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# change to grpc repo root
+cd $(dirname $0)/../../..
+
+git submodule update --init
+
+# TODO(ericgribkoff) Remove when this commit (already in master) is included in
+# next protobuf release
+cd third_party/protobuf
+git fetch
+git cherry-pick 7daa320065f3bea2b54bf983337d1724f153422d -m 1
+
+cd ../../examples/android/helloworld
+./gradlew build
diff --git a/tools/interop_matrix/client_matrix.py b/tools/interop_matrix/client_matrix.py
index 722cf8a..aa45f7f 100644
--- a/tools/interop_matrix/client_matrix.py
+++ b/tools/interop_matrix/client_matrix.py
@@ -84,6 +84,9 @@
{
'v1.9.1': None
},
+ {
+ 'v1.10.0': None
+ },
],
'go': [
{
@@ -149,7 +152,7 @@
'v1.9.1': None
},
{
- 'v1.10.0': None
+ 'v1.10.1': None
},
],
'python': [
@@ -180,6 +183,9 @@
{
'v1.9.1': None
},
+ {
+ 'v1.10.0': None
+ },
],
'node': [
{
@@ -209,7 +215,10 @@
},
{
'v1.9.1': None
- }
+ },
+ {
+ 'v1.10.0': None
+ },
],
'ruby': [
{
@@ -244,6 +253,9 @@
{
'v1.9.1': None
},
+ {
+ 'v1.10.0': None
+ },
],
'php': [
{
@@ -273,6 +285,9 @@
{
'v1.9.1': None
},
+ {
+ 'v1.10.0': None
+ },
],
'csharp': [
#{'v1.0.1': None},
@@ -300,6 +315,9 @@
{
'v1.9.1': None
},
+ {
+ 'v1.10.0': None
+ },
],
}
diff --git a/tools/profiling/latency_profile/profile_analyzer.py b/tools/profiling/latency_profile/profile_analyzer.py
index d4d14ef..cdc2f1c 100755
--- a/tools/profiling/latency_profile/profile_analyzer.py
+++ b/tools/profiling/latency_profile/profile_analyzer.py
@@ -184,24 +184,23 @@
def percentile(N, percent, key=lambda x: x):
"""
- Find the percentile of a list of values.
+ Find the percentile of an already sorted list of values.
- @parameter N - is a list of values. Note N MUST BE already sorted.
- @parameter percent - a float value from 0.0 to 1.0.
+ @parameter N - is a list of values. MUST be already sorted.
+ @parameter percent - a float value from [0.0,1.0].
@parameter key - optional key function to compute value from each element of N.
@return - the percentile of the values
"""
if not N:
return None
- k = (len(N) - 1) * percent
- f = math.floor(k)
- c = math.ceil(k)
- if f == c:
- return key(N[int(k)])
- d0 = key(N[int(f)]) * (c - k)
- d1 = key(N[int(c)]) * (k - f)
- return d0 + d1
+ float_idx = (len(N) - 1) * percent
+ idx = int(float_idx)
+ result = key(N[idx])
+ if idx < len(N) - 1:
+ # interpolate with the next element's value
+ result += (float_idx - idx) * (key(N[idx + 1]) - key(N[idx]))
+ return result
def tidy_tag(tag):