Merge branch 'master' of github.com:grpc/grpc into authority_header

reviewable/pr14615/r18
David Garcia Quintas 7 years ago
commit 811169d62f
  1. 1
      examples/cpp/route_guide/route_guide_server.cc
  2. 21
      examples/csharp/route_guide/RouteGuide/RouteGuideUtil.cs
  3. 27
      examples/node/dynamic_codegen/route_guide/route_guide_server.js
  4. 27
      examples/node/static_codegen/route_guide/route_guide_server.js
  5. 1
      examples/python/route_guide/route_guide_server.py
  6. 21
      examples/ruby/route_guide/route_guide_server.rb
  7. 15
      include/grpcpp/impl/codegen/call.h
  8. 8
      include/grpcpp/server.h
  9. 82
      src/core/ext/filters/client_channel/client_channel.cc
  10. 4
      src/core/ext/filters/client_channel/resolver.h
  11. 30
      src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc
  12. 5
      src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h
  13. 4
      src/core/ext/transport/chttp2/transport/chttp2_transport.cc
  14. 4
      src/core/ext/transport/chttp2/transport/parsing.cc
  15. 14
      src/core/ext/transport/chttp2/transport/writing.cc
  16. 57
      src/cpp/server/server_cc.cc
  17. 13
      src/csharp/Grpc.Core/Channel.cs
  18. 5
      src/python/grpcio/grpc/_cython/_cygrpc/call.pyx.pxi
  19. 1
      src/ruby/ext/grpc/extconf.rb
  20. 2
      src/ruby/ext/grpc/rb_compression_options.c
  21. 57
      templates/tools/dockerfile/test/cxx_alpine_x64/Dockerfile.template
  22. 70
      test/core/end2end/no_server_test.cc
  23. 164
      test/core/end2end/tests/bad_ping.cc
  24. 2
      test/core/end2end/tests/keepalive_timeout.cc
  25. 2
      test/distrib/php/run_distrib_test.sh
  26. 18
      tools/dockerfile/test/cxx_alpine_x64/Dockerfile
  27. 19
      tools/internal_ci/linux/grpc_android.cfg
  28. 30
      tools/internal_ci/linux/grpc_android.sh
  29. 22
      tools/interop_matrix/client_matrix.py
  30. 21
      tools/profiling/latency_profile/profile_analyzer.py

@ -51,6 +51,7 @@ float ConvertToRadians(float num) {
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;

@ -52,26 +52,23 @@ namespace Routeguide
/// <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;
}

@ -103,7 +103,7 @@ function listFeatures(call) {
/**
* 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 getDistance(start, end) {
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 a = Math.sin(Δφ/2) * Math.sin(Δφ/2) +
Math.cos(φ1) * Math.cos(φ2) *
Math.sin(Δλ/2) * Math.sin(Δλ/2);
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 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;
}

@ -102,7 +102,7 @@ function listFeatures(call) {
/**
* 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 getDistance(start, end) {
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 a = Math.sin(Δφ/2) * Math.sin(Δφ/2) +
Math.cos(φ1) * Math.cos(φ2) *
Math.sin(Δλ/2) * Math.sin(Δλ/2);
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 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;
}

@ -46,6 +46,7 @@ def get_distance(start, end):
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)))

@ -32,19 +32,18 @@ COORD_FACTOR = 1e7
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

@ -656,21 +656,6 @@ class CallOpSet : public CallOpSetInterface,
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:

@ -162,8 +162,8 @@ class Server : public ServerInterface, private GrpcLibraryCodegen {
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 @@ class Server : public ServerInterface, private GrpcLibraryCodegen {
/// 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;

@ -303,11 +303,16 @@ static void request_reresolution_locked(void* arg, grpc_error* error) {
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 @@ static void on_resolver_result_changed_locked(void* arg, grpc_error* error) {
}
}
}
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 @@ static void on_resolver_result_changed_locked(void* arg, grpc_error* error) {
"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 @@ static void on_resolver_result_changed_locked(void* arg, grpc_error* error) {
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 @@ static void pick_after_resolver_result_done_locked(void* arg,
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 @@ static void pick_after_resolver_result_done_locked(void* arg,
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) {

@ -53,8 +53,12 @@ class Resolver : public InternallyRefCountedWithTracing<Resolver> {
/// 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

@ -82,6 +82,8 @@ class FakeResolver : public Resolver {
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::RequestReresolutionLocked() {
}
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 @@ void FakeResolverResponseGenerator::SetReresolutionResponse(
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) {

@ -56,6 +56,10 @@ class FakeResolverResponseGenerator
// 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 @@ class FakeResolverResponseGenerator
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.
};

@ -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 @@ static void start_keepalive_ping_locked(void* arg, grpc_error* error) {
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);
}

@ -373,8 +373,6 @@ error_handler:
/* 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 @@ static grpc_error* init_header_frame_parser(grpc_chttp2_transport* t,
(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 */

@ -224,7 +224,7 @@ class WriteContext {
grpc_slice_buffer_add(
&t_->outbuf, grpc_chttp2_window_update_create(0, transport_announce,
&throwaway_stats));
ResetPingRecvClock();
ResetPingClock();
}
}
@ -269,11 +269,13 @@ class WriteContext {
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 @@ class StreamWriteContext {
};
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 @@ class StreamWriteContext {
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 @@ class StreamWriteContext {
data_send_context.CompressMoreBytes();
}
}
write_context_->ResetPingRecvClock();
write_context_->ResetPingClock();
if (data_send_context.is_last_frame()) {
SentLastFrame();
}
@ -530,7 +532,7 @@ class StreamWriteContext {
s_->send_trailing_metadata, &hopt, &t_->outbuf);
}
write_context_->IncTrailingMetadataWrites();
write_context_->ResetPingRecvClock();
write_context_->ResetPingClock();
SentLastFrame();
write_context_->NoteScheduledResults();

@ -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 @@ class DefaultGlobalCallbacks final : public Server::GlobalCallbacks {
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 @@ class Server::UnimplementedAsyncRequestContext {
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 @@ class Server::UnimplementedAsyncRequest final
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)

@ -160,8 +160,17 @@ namespace Grpc.Core
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;
}

@ -30,9 +30,12 @@ cdef class Call:
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

@ -94,7 +94,6 @@ $CFLAGS << ' -std=c99 '
$CFLAGS << ' -Wall '
$CFLAGS << ' -Wextra '
$CFLAGS << ' -pedantic '
$CFLAGS << ' -Wno-format '
output = File.join('grpc', 'grpc_c')
puts 'Generating Makefile for ' + output

@ -186,7 +186,7 @@ void grpc_rb_compression_options_algorithm_name_to_value_internal(
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);

@ -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"]

@ -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 @@ int main(int argc, char** argv) {
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 @@ int main(int argc, char** argv) {
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;
}

@ -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 @@ static void end_test(grpc_end2end_test_fixture* f) {
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 @@ static void test_bad_ping(grpc_end2end_test_config config) {
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) {}

@ -102,7 +102,7 @@ static void test_keepalive_timeout(grpc_end2end_test_config config) {
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;

@ -20,6 +20,6 @@ cd "$(dirname "$0")"
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

@ -39,23 +39,27 @@ RUN apk update && apk add \
# 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
# 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
# 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/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++
# 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
RUN mkdir /var/local/jenkins
# Define the default command.
CMD ["bash"]

@ -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

@ -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

@ -84,6 +84,9 @@ LANG_RELEASE_MATRIX = {
{
'v1.9.1': None
},
{
'v1.10.0': None
},
],
'go': [
{
@ -149,7 +152,7 @@ LANG_RELEASE_MATRIX = {
'v1.9.1': None
},
{
'v1.10.0': None
'v1.10.1': None
},
],
'python': [
@ -180,6 +183,9 @@ LANG_RELEASE_MATRIX = {
{
'v1.9.1': None
},
{
'v1.10.0': None
},
],
'node': [
{
@ -209,7 +215,10 @@ LANG_RELEASE_MATRIX = {
},
{
'v1.9.1': None
}
},
{
'v1.10.0': None
},
],
'ruby': [
{
@ -244,6 +253,9 @@ LANG_RELEASE_MATRIX = {
{
'v1.9.1': None
},
{
'v1.10.0': None
},
],
'php': [
{
@ -273,6 +285,9 @@ LANG_RELEASE_MATRIX = {
{
'v1.9.1': None
},
{
'v1.10.0': None
},
],
'csharp': [
#{'v1.0.1': None},
@ -300,6 +315,9 @@ LANG_RELEASE_MATRIX = {
{
'v1.9.1': None
},
{
'v1.10.0': None
},
],
}

@ -184,24 +184,23 @@ for cs in call_stacks:
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):

Loading…
Cancel
Save