diff --git a/doc/cpp/perf_notes.md b/doc/cpp/perf_notes.md new file mode 100644 index 00000000000..c87557558dd --- /dev/null +++ b/doc/cpp/perf_notes.md @@ -0,0 +1,29 @@ +# C++ Performance Notes + +## Streaming write buffering + +Generally, each write operation (Write(), WritesDone()) implies a syscall. +gRPC will try to batch together separate write operations from different +threads, but currently cannot automatically infer batching in a single stream. + +If message k+1 in a stream does not rely on responses from message k, it's +possible to enable write batching by passing a WriteOptions argument to Write +with the buffer_hint set: + +~~~{.cpp} +stream_writer->Write(message, WriteOptions().set_buffer_hint()); +~~~ + +The write will be buffered until one of the following is true: +- the per-stream buffer is filled (controllable with the channel argument + GRPC_ARG_HTTP2_WRITE_BUFFER_SIZE) - this prevents infinite buffering leading + to OOM +- a subsequent Write without buffer_hint set is posted +- the call is finished for writing (WritesDone() called on the client, + or Finish() called on an async server stream, or the service handler returns + for a sync server stream) + +## Completion Queues and Threading in the Async API + +Right now, the best performance trade-off is having numcpu's threads and one +completion queue per thread. diff --git a/doc/interop-test-descriptions.md b/doc/interop-test-descriptions.md index 96d1f2bd752..da3b9767443 100644 --- a/doc/interop-test-descriptions.md +++ b/doc/interop-test-descriptions.md @@ -716,7 +716,9 @@ Procedure: ``` { - response_size: 314159 + response_parameters:{ + size: 314159 + } payload:{ body: 271828 bytes of zeros } diff --git a/include/grpc++/grpc++.h b/include/grpc++/grpc++.h index 36d65d6ee1e..daecfea4069 100644 --- a/include/grpc++/grpc++.h +++ b/include/grpc++/grpc++.h @@ -44,6 +44,10 @@ /// peer, compression settings, authentication, etc. /// - grpc::Server, representing a gRPC server, created by grpc::ServerBuilder. /// +/// Streaming calls are handled with the streaming classes in +/// \ref sync_stream.h and +/// \ref async_stream.h. +/// /// Refer to the /// [examples](https://github.com/grpc/grpc/blob/master/examples/cpp) /// for code putting these pieces into play. diff --git a/include/grpc++/impl/codegen/completion_queue.h b/include/grpc++/impl/codegen/completion_queue.h index 944f2c39198..03cecdc21c6 100644 --- a/include/grpc++/impl/codegen/completion_queue.h +++ b/include/grpc++/impl/codegen/completion_queue.h @@ -94,8 +94,10 @@ class ServerContext; extern CoreCodegenInterface* g_core_codegen_interface; -/// A thin wrapper around \a grpc_completion_queue (see / \a -/// src/core/surface/completion_queue.h). +/// A thin wrapper around \ref grpc_completion_queue (see \ref +/// src/core/lib/surface/completion_queue.h). +/// See \ref doc/cpp/perf_notes.md for notes on best practices for high +/// performance servers. class CompletionQueue : private GrpcLibraryCodegen { public: /// Default constructor. Implicitly creates a \a grpc_completion_queue diff --git a/src/core/ext/README.md b/src/core/ext/README.md new file mode 100644 index 00000000000..0812b20823c --- /dev/null +++ b/src/core/ext/README.md @@ -0,0 +1,5 @@ +Optional plugins for gRPC Core: Modules in this directory extend gRPC Core in +useful ways. All optional code belongs here. + +NOTE: The movement of code between lib and ext is an ongoing effort, so this +directory currently contains too much of the core library. diff --git a/src/core/ext/client_channel/channel_connectivity.c b/src/core/ext/client_channel/channel_connectivity.c index b10f444b63f..dd70bc2c6c8 100644 --- a/src/core/ext/client_channel/channel_connectivity.c +++ b/src/core/ext/client_channel/channel_connectivity.c @@ -76,6 +76,7 @@ typedef struct { gpr_mu mu; callback_phase phase; grpc_closure on_complete; + grpc_closure on_timeout; grpc_timer alarm; grpc_connectivity_state state; grpc_completion_queue *cq; @@ -200,6 +201,8 @@ void grpc_channel_watch_connectivity_state( gpr_mu_init(&w->mu); grpc_closure_init(&w->on_complete, watch_complete, w, grpc_schedule_on_exec_ctx); + grpc_closure_init(&w->on_timeout, timeout_complete, w, + grpc_schedule_on_exec_ctx); w->phase = WAITING; w->state = last_observed_state; w->cq = cq; @@ -208,7 +211,7 @@ void grpc_channel_watch_connectivity_state( grpc_timer_init(&exec_ctx, &w->alarm, gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC), - timeout_complete, w, gpr_now(GPR_CLOCK_MONOTONIC)); + &w->on_timeout, gpr_now(GPR_CLOCK_MONOTONIC)); if (client_channel_elem->filter == &grpc_client_channel_filter) { GRPC_CHANNEL_INTERNAL_REF(channel, "watch_channel_connectivity"); diff --git a/src/core/ext/client_channel/subchannel.c b/src/core/ext/client_channel/subchannel.c index fad5c69c83e..1bac82b4512 100644 --- a/src/core/ext/client_channel/subchannel.c +++ b/src/core/ext/client_channel/subchannel.c @@ -109,6 +109,9 @@ struct grpc_subchannel { /** callback for connection finishing */ grpc_closure connected; + /** callback for our alarm */ + grpc_closure on_alarm; + /** pollset_set tracking who's interested in a connection being setup */ grpc_pollset_set *pollset_set; @@ -483,7 +486,8 @@ static void maybe_start_connecting_locked(grpc_exec_ctx *exec_ctx, gpr_log(GPR_INFO, "Retry in %" PRId64 ".%09d seconds", time_til_next.tv_sec, time_til_next.tv_nsec); } - grpc_timer_init(exec_ctx, &c->alarm, c->next_attempt, on_alarm, c, now); + 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, now); } } diff --git a/src/core/ext/lb_policy/grpclb/grpclb.c b/src/core/ext/lb_policy/grpclb/grpclb.c index 2d48a3a9e74..97f98df03af 100644 --- a/src/core/ext/lb_policy/grpclb/grpclb.c +++ b/src/core/ext/lb_policy/grpclb/grpclb.c @@ -327,6 +327,9 @@ typedef struct glb_lb_policy { /* A response from the LB server has been received. Process it */ grpc_closure lb_on_response_received; + /* LB call retry timer callback. */ + grpc_closure lb_on_call_retry; + grpc_call *lb_call; /* streaming call to the LB server, */ grpc_metadata_array lb_initial_metadata_recv; /* initial MD from LB server */ @@ -1364,8 +1367,10 @@ static void lb_on_server_status_received(grpc_exec_ctx *exec_ctx, void *arg, } } GRPC_LB_POLICY_WEAK_REF(&glb_policy->base, "grpclb_retry_timer"); + grpc_closure_init(&glb_policy->lb_on_call_retry, lb_call_on_retry_timer, + glb_policy, grpc_schedule_on_exec_ctx); grpc_timer_init(exec_ctx, &glb_policy->lb_call_retry_timer, next_try, - lb_call_on_retry_timer, glb_policy, now); + &glb_policy->lb_on_call_retry, now); } gpr_mu_unlock(&glb_policy->mu); GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &glb_policy->base, diff --git a/src/core/ext/resolver/README.md b/src/core/ext/resolver/README.md new file mode 100644 index 00000000000..b0e234e96a5 --- /dev/null +++ b/src/core/ext/resolver/README.md @@ -0,0 +1,4 @@ +# Resolver + +Implementations of various name resolution schemes. +See the [naming spec](/doc/naming.md). diff --git a/src/core/ext/resolver/dns/native/dns_resolver.c b/src/core/ext/resolver/dns/native/dns_resolver.c index 124b16bbc38..bb2b0125072 100644 --- a/src/core/ext/resolver/dns/native/dns_resolver.c +++ b/src/core/ext/resolver/dns/native/dns_resolver.c @@ -81,6 +81,7 @@ typedef struct { /** retry timer */ bool have_retry_timer; grpc_timer retry_timer; + grpc_closure on_retry; /** retry backoff state */ gpr_backoff backoff_state; @@ -199,8 +200,9 @@ static void dns_on_resolved(grpc_exec_ctx *exec_ctx, void *arg, } else { gpr_log(GPR_DEBUG, "retrying immediately"); } - grpc_timer_init(exec_ctx, &r->retry_timer, next_try, dns_on_retry_timer, r, - now); + grpc_closure_init(&r->on_retry, dns_on_retry_timer, r, + grpc_schedule_on_exec_ctx); + grpc_timer_init(exec_ctx, &r->retry_timer, next_try, &r->on_retry, now); } if (r->resolved_result != NULL) { grpc_channel_args_destroy(exec_ctx, r->resolved_result); diff --git a/src/core/ext/transport/README.md b/src/core/ext/transport/README.md new file mode 100644 index 00000000000..2290568784d --- /dev/null +++ b/src/core/ext/transport/README.md @@ -0,0 +1 @@ +Transports for gRPC diff --git a/src/core/ext/transport/chttp2/README.md b/src/core/ext/transport/chttp2/README.md new file mode 100644 index 00000000000..8880a47460a --- /dev/null +++ b/src/core/ext/transport/chttp2/README.md @@ -0,0 +1 @@ +CHTTP2 - gRPC's implementation of a HTTP2 based transport diff --git a/src/core/lib/README.md b/src/core/lib/README.md new file mode 100644 index 00000000000..69b6bce2d9f --- /dev/null +++ b/src/core/lib/README.md @@ -0,0 +1,6 @@ +Required elements of gRPC Core: Each module in this directory is required to +build gRPC. If it's possible to envisage a configuration where code is not +required, then that code belongs in ext/ instead. + +NOTE: The movement of code between lib and ext is an ongoing effort, so this +directory currently contains too much of the core library. diff --git a/src/core/lib/channel/README.md b/src/core/lib/channel/README.md new file mode 100644 index 00000000000..2dfcfe6e662 --- /dev/null +++ b/src/core/lib/channel/README.md @@ -0,0 +1,4 @@ +# Channel + +Provides channel/call stack implementation, and implementation of common filters +for that implementation. diff --git a/src/core/lib/channel/deadline_filter.c b/src/core/lib/channel/deadline_filter.c index 8dd6d099e1d..a45a4d4b820 100644 --- a/src/core/lib/channel/deadline_filter.c +++ b/src/core/lib/channel/deadline_filter.c @@ -83,8 +83,11 @@ static void start_timer_if_needed_locked(grpc_exec_ctx* exec_ctx, // Take a reference to the call stack, to be owned by the timer. GRPC_CALL_STACK_REF(deadline_state->call_stack, "deadline_timer"); deadline_state->timer_pending = true; - grpc_timer_init(exec_ctx, &deadline_state->timer, deadline, timer_callback, - elem, gpr_now(GPR_CLOCK_MONOTONIC)); + grpc_closure_init(&deadline_state->timer_callback, timer_callback, elem, + grpc_schedule_on_exec_ctx); + grpc_timer_init(exec_ctx, &deadline_state->timer, deadline, + &deadline_state->timer_callback, + gpr_now(GPR_CLOCK_MONOTONIC)); } } static void start_timer_if_needed(grpc_exec_ctx* exec_ctx, diff --git a/src/core/lib/channel/deadline_filter.h b/src/core/lib/channel/deadline_filter.h index 716a8525653..bd2b84f79e1 100644 --- a/src/core/lib/channel/deadline_filter.h +++ b/src/core/lib/channel/deadline_filter.h @@ -46,6 +46,7 @@ typedef struct grpc_deadline_state { bool timer_pending; // The deadline timer. grpc_timer timer; + grpc_closure timer_callback; // Closure to invoke when the call is complete. // We use this to cancel the timer. grpc_closure on_complete; diff --git a/src/core/lib/channel/handshaker.c b/src/core/lib/channel/handshaker.c index ff827527b3e..c052ca53852 100644 --- a/src/core/lib/channel/handshaker.c +++ b/src/core/lib/channel/handshaker.c @@ -86,6 +86,7 @@ struct grpc_handshake_manager { grpc_tcp_server_acceptor* acceptor; // Deadline timer across all handshakers. grpc_timer deadline_timer; + grpc_closure on_timeout; // The final callback and user_data to invoke after the last handshaker. grpc_closure on_handshake_done; void* user_data; @@ -224,9 +225,11 @@ void grpc_handshake_manager_do_handshake( grpc_schedule_on_exec_ctx); // Start deadline timer, which owns a ref. gpr_ref(&mgr->refs); + grpc_closure_init(&mgr->on_timeout, on_timeout, mgr, + grpc_schedule_on_exec_ctx); grpc_timer_init(exec_ctx, &mgr->deadline_timer, gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC), - on_timeout, mgr, gpr_now(GPR_CLOCK_MONOTONIC)); + &mgr->on_timeout, gpr_now(GPR_CLOCK_MONOTONIC)); // Start first handshaker, which also owns a ref. gpr_ref(&mgr->refs); bool done = call_next_handshaker_locked(exec_ctx, mgr, GRPC_ERROR_NONE); diff --git a/src/core/lib/iomgr/README.md b/src/core/lib/iomgr/README.md new file mode 100644 index 00000000000..9b22b76cebf --- /dev/null +++ b/src/core/lib/iomgr/README.md @@ -0,0 +1,6 @@ +# iomgr + +Platform abstractions for I/O (mostly network). + +Provides abstractions over TCP/UDP I/O, file loading, polling, and concurrency +management for various operating systems. diff --git a/src/core/lib/iomgr/tcp_client_posix.c b/src/core/lib/iomgr/tcp_client_posix.c index c8237dc38f1..9a77c92016b 100644 --- a/src/core/lib/iomgr/tcp_client_posix.c +++ b/src/core/lib/iomgr/tcp_client_posix.c @@ -65,6 +65,7 @@ typedef struct { grpc_fd *fd; gpr_timespec deadline; grpc_timer alarm; + grpc_closure on_alarm; int refs; grpc_closure write_closure; grpc_pollset_set *interested_parties; @@ -352,9 +353,10 @@ static void tcp_client_connect_impl(grpc_exec_ctx *exec_ctx, } gpr_mu_lock(&ac->mu); + grpc_closure_init(&ac->on_alarm, tc_on_alarm, ac, grpc_schedule_on_exec_ctx); grpc_timer_init(exec_ctx, &ac->alarm, gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC), - tc_on_alarm, ac, gpr_now(GPR_CLOCK_MONOTONIC)); + &ac->on_alarm, gpr_now(GPR_CLOCK_MONOTONIC)); grpc_fd_notify_on_write(exec_ctx, ac->fd, &ac->write_closure); gpr_mu_unlock(&ac->mu); diff --git a/src/core/lib/iomgr/tcp_client_uv.c b/src/core/lib/iomgr/tcp_client_uv.c index ed0de50fc12..5225a5402b2 100644 --- a/src/core/lib/iomgr/tcp_client_uv.c +++ b/src/core/lib/iomgr/tcp_client_uv.c @@ -49,6 +49,7 @@ typedef struct grpc_uv_tcp_connect { uv_connect_t connect_req; grpc_timer alarm; + grpc_closure on_alarm; uv_tcp_t *tcp_handle; grpc_closure *closure; grpc_endpoint **endpoint; @@ -148,9 +149,11 @@ static void tcp_client_connect_impl(grpc_exec_ctx *exec_ctx, uv_tcp_connect(&connect->connect_req, connect->tcp_handle, (const struct sockaddr *)resolved_addr->addr, uv_tc_on_connect); + grpc_closure_init(&connect->on_alarm, uv_tc_on_alarm, connect, + grpc_schedule_on_exec_ctx); grpc_timer_init(exec_ctx, &connect->alarm, gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC), - uv_tc_on_alarm, connect, gpr_now(GPR_CLOCK_MONOTONIC)); + &connect->on_alarm, gpr_now(GPR_CLOCK_MONOTONIC)); } // overridden by api_fuzzer.c diff --git a/src/core/lib/iomgr/tcp_client_windows.c b/src/core/lib/iomgr/tcp_client_windows.c index 275258ebb5d..1e84ec3a1ec 100644 --- a/src/core/lib/iomgr/tcp_client_windows.c +++ b/src/core/lib/iomgr/tcp_client_windows.c @@ -58,6 +58,7 @@ typedef struct { grpc_winsocket *socket; gpr_timespec deadline; grpc_timer alarm; + grpc_closure on_alarm; char *addr_name; int refs; grpc_closure on_connect; @@ -229,7 +230,8 @@ void grpc_tcp_client_connect(grpc_exec_ctx *exec_ctx, grpc_closure *on_done, ac->resource_quota = resource_quota; grpc_closure_init(&ac->on_connect, on_connect, ac, grpc_schedule_on_exec_ctx); - grpc_timer_init(exec_ctx, &ac->alarm, deadline, on_alarm, ac, + grpc_closure_init(&ac->on_alarm, on_alarm, ac, grpc_schedule_on_exec_ctx); + grpc_timer_init(exec_ctx, &ac->alarm, deadline, &ac->on_alarm, gpr_now(GPR_CLOCK_MONOTONIC)); grpc_socket_notify_on_write(exec_ctx, socket, &ac->on_connect); return; diff --git a/src/core/lib/iomgr/timer.h b/src/core/lib/iomgr/timer.h index 20fe98c4a7d..d84a278b183 100644 --- a/src/core/lib/iomgr/timer.h +++ b/src/core/lib/iomgr/timer.h @@ -49,15 +49,15 @@ typedef struct grpc_timer grpc_timer; -/* Initialize *timer. When expired or canceled, timer_cb will be called with - *timer_cb_arg and error set to indicate if it expired (GRPC_ERROR_NONE) or - was canceled (GRPC_ERROR_CANCELLED). timer_cb is guaranteed to be called - exactly once, and application code should check the error to determine - how it was invoked. The application callback is also responsible for - maintaining information about when to free up any user-level state. */ +/* Initialize *timer. When expired or canceled, closure will be called with + error set to indicate if it expired (GRPC_ERROR_NONE) or was canceled + (GRPC_ERROR_CANCELLED). timer_cb is guaranteed to be called exactly once, and + application code should check the error to determine how it was invoked. The + application callback is also responsible for maintaining information about + when to free up any user-level state. */ void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer, - gpr_timespec deadline, grpc_iomgr_cb_func timer_cb, - void *timer_cb_arg, gpr_timespec now); + gpr_timespec deadline, grpc_closure *closure, + gpr_timespec now); /* Note that there is no timer destroy function. This is because the timer is a one-time occurrence with a guarantee that the callback will diff --git a/src/core/lib/iomgr/timer_generic.c b/src/core/lib/iomgr/timer_generic.c index ecd3b284dc2..40c83514724 100644 --- a/src/core/lib/iomgr/timer_generic.c +++ b/src/core/lib/iomgr/timer_generic.c @@ -178,28 +178,27 @@ static void note_deadline_change(shard_type *shard) { } void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer, - gpr_timespec deadline, grpc_iomgr_cb_func timer_cb, - void *timer_cb_arg, gpr_timespec now) { + gpr_timespec deadline, grpc_closure *closure, + gpr_timespec now) { int is_first_timer = 0; shard_type *shard = &g_shards[shard_idx(timer)]; GPR_ASSERT(deadline.clock_type == g_clock_type); GPR_ASSERT(now.clock_type == g_clock_type); - grpc_closure_init(&timer->closure, timer_cb, timer_cb_arg, - grpc_schedule_on_exec_ctx); + timer->closure = closure; timer->deadline = deadline; timer->triggered = 0; if (!g_initialized) { timer->triggered = 1; grpc_closure_sched( - exec_ctx, &timer->closure, + exec_ctx, timer->closure, GRPC_ERROR_CREATE("Attempt to create timer before initialization")); return; } if (gpr_time_cmp(deadline, now) <= 0) { timer->triggered = 1; - grpc_closure_sched(exec_ctx, &timer->closure, GRPC_ERROR_NONE); + grpc_closure_sched(exec_ctx, timer->closure, GRPC_ERROR_NONE); return; } @@ -251,7 +250,7 @@ void grpc_timer_cancel(grpc_exec_ctx *exec_ctx, grpc_timer *timer) { shard_type *shard = &g_shards[shard_idx(timer)]; gpr_mu_lock(&shard->mu); if (!timer->triggered) { - grpc_closure_sched(exec_ctx, &timer->closure, GRPC_ERROR_CANCELLED); + grpc_closure_sched(exec_ctx, timer->closure, GRPC_ERROR_CANCELLED); timer->triggered = 1; if (timer->heap_index == INVALID_HEAP_INDEX) { list_remove(timer); @@ -317,7 +316,7 @@ static size_t pop_timers(grpc_exec_ctx *exec_ctx, shard_type *shard, grpc_timer *timer; gpr_mu_lock(&shard->mu); while ((timer = pop_one(shard, now))) { - grpc_closure_sched(exec_ctx, &timer->closure, GRPC_ERROR_REF(error)); + grpc_closure_sched(exec_ctx, timer->closure, GRPC_ERROR_REF(error)); n++; } *new_min_deadline = compute_min_deadline(shard); diff --git a/src/core/lib/iomgr/timer_generic.h b/src/core/lib/iomgr/timer_generic.h index e4494adb5fe..9d901c7e68f 100644 --- a/src/core/lib/iomgr/timer_generic.h +++ b/src/core/lib/iomgr/timer_generic.h @@ -43,7 +43,7 @@ struct grpc_timer { int triggered; struct grpc_timer *next; struct grpc_timer *prev; - grpc_closure closure; + grpc_closure *closure; }; #endif /* GRPC_CORE_LIB_IOMGR_TIMER_GENERIC_H */ diff --git a/src/core/lib/iomgr/timer_uv.c b/src/core/lib/iomgr/timer_uv.c index 00b835ffb80..fa2cdee9646 100644 --- a/src/core/lib/iomgr/timer_uv.c +++ b/src/core/lib/iomgr/timer_uv.c @@ -55,21 +55,20 @@ void run_expired_timer(uv_timer_t *handle) { grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; GPR_ASSERT(!timer->triggered); timer->triggered = 1; - grpc_closure_sched(&exec_ctx, &timer->closure, GRPC_ERROR_NONE); + grpc_closure_sched(&exec_ctx, timer->closure, GRPC_ERROR_NONE); stop_uv_timer(handle); grpc_exec_ctx_finish(&exec_ctx); } void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer, - gpr_timespec deadline, grpc_iomgr_cb_func timer_cb, - void *timer_cb_arg, gpr_timespec now) { + gpr_timespec deadline, grpc_closure *closure, + gpr_timespec now) { uint64_t timeout; uv_timer_t *uv_timer; - grpc_closure_init(&timer->closure, timer_cb, timer_cb_arg, - grpc_schedule_on_exec_ctx); + timer->closure = closure; if (gpr_time_cmp(deadline, now) <= 0) { timer->triggered = 1; - grpc_closure_sched(exec_ctx, &timer->closure, GRPC_ERROR_NONE); + grpc_closure_sched(exec_ctx, timer->closure, GRPC_ERROR_NONE); return; } timer->triggered = 0; @@ -84,7 +83,7 @@ void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer, void grpc_timer_cancel(grpc_exec_ctx *exec_ctx, grpc_timer *timer) { if (!timer->triggered) { timer->triggered = 1; - grpc_closure_sched(exec_ctx, &timer->closure, GRPC_ERROR_CANCELLED); + grpc_closure_sched(exec_ctx, timer->closure, GRPC_ERROR_CANCELLED); stop_uv_timer((uv_timer_t *)timer->uv_timer); } } diff --git a/src/core/lib/iomgr/timer_uv.h b/src/core/lib/iomgr/timer_uv.h index 3de383ebd50..13cf8bd4fa0 100644 --- a/src/core/lib/iomgr/timer_uv.h +++ b/src/core/lib/iomgr/timer_uv.h @@ -37,7 +37,7 @@ #include "src/core/lib/iomgr/exec_ctx.h" struct grpc_timer { - grpc_closure closure; + grpc_closure *closure; /* This is actually a uv_timer_t*, but we want to keep platform-specific types out of headers */ void *uv_timer; diff --git a/src/core/lib/surface/README.md b/src/core/lib/surface/README.md new file mode 100644 index 00000000000..74cbd711315 --- /dev/null +++ b/src/core/lib/surface/README.md @@ -0,0 +1,4 @@ +# Surface + +Surface provides the bulk of the gRPC Core public API, and translates it into +calls against core components. diff --git a/src/core/lib/surface/alarm.c b/src/core/lib/surface/alarm.c index aa9d60ee6a8..e71c0ebfc57 100644 --- a/src/core/lib/surface/alarm.c +++ b/src/core/lib/surface/alarm.c @@ -38,6 +38,7 @@ struct grpc_alarm { grpc_timer alarm; + grpc_closure on_alarm; grpc_cq_completion completion; /** completion queue where events about this alarm will be posted */ grpc_completion_queue *cq; @@ -64,9 +65,11 @@ grpc_alarm *grpc_alarm_create(grpc_completion_queue *cq, gpr_timespec deadline, alarm->tag = tag; grpc_cq_begin_op(cq, tag); + grpc_closure_init(&alarm->on_alarm, alarm_cb, alarm, + grpc_schedule_on_exec_ctx); grpc_timer_init(&exec_ctx, &alarm->alarm, gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC), - alarm_cb, alarm, gpr_now(GPR_CLOCK_MONOTONIC)); + &alarm->on_alarm, gpr_now(GPR_CLOCK_MONOTONIC)); grpc_exec_ctx_finish(&exec_ctx); return alarm; } diff --git a/src/core/lib/transport/README.md b/src/core/lib/transport/README.md new file mode 100644 index 00000000000..e7e135edeb1 --- /dev/null +++ b/src/core/lib/transport/README.md @@ -0,0 +1,7 @@ +# Transport + +Common implementation details for gRPC Transports. + +Transports multiplex messages across some single connection. In ext/ there are +implementations atop [a custom http2 implementation](/src/core/ext/transport/chttp2/README.md) +and atop [cronet](/src/core/ext/transport/cronet/README.md). diff --git a/src/core/lib/tsi/README.md b/src/core/lib/tsi/README.md new file mode 100644 index 00000000000..3ca3c1ef38c --- /dev/null +++ b/src/core/lib/tsi/README.md @@ -0,0 +1,2 @@ +# Transport Security Interface +An abstraction library over crypto and auth modules (typically OpenSSL) diff --git a/src/node/interop/interop_client.js b/src/node/interop/interop_client.js index 46ddecfb1f6..75cfb41342f 100644 --- a/src/node/interop/interop_client.js +++ b/src/node/interop/interop_client.js @@ -312,6 +312,9 @@ function customMetadata(client, done) { } }; var streaming_arg = { + response_parameters: [ + {size: 314159} + ], payload: { body: zeroBuffer(271828) } diff --git a/src/php/tests/interop/interop_client.php b/src/php/tests/interop/interop_client.php index d201915d668..2acf5612c7e 100755 --- a/src/php/tests/interop/interop_client.php +++ b/src/php/tests/interop/interop_client.php @@ -451,11 +451,22 @@ function customMetadata($stub) $streaming_request = new grpc\testing\StreamingOutputCallRequest(); $streaming_request->setPayload($payload); + $response_parameters = new grpc\testing\ResponseParameters(); + $response_parameters->setSize($response_len); + $streaming_request->getResponseParameters()[] = $response_parameters; $streaming_call->write($streaming_request); $streaming_call->writesDone(); + $result = $streaming_call->read(); hardAssertIfStatusOk($streaming_call->getStatus()); + $streaming_initial_metadata = $streaming_call->getMetadata(); + hardAssert(array_key_exists($ECHO_INITIAL_KEY, $streaming_initial_metadata), + 'Initial metadata does not contain expected key'); + hardAssert( + $streaming_initial_metadata[$ECHO_INITIAL_KEY][0] === $ECHO_INITIAL_VALUE, + 'Incorrect initial metadata value'); + $streaming_trailing_metadata = $streaming_call->getTrailingMetadata(); hardAssert(array_key_exists($ECHO_TRAILING_KEY, $streaming_trailing_metadata), diff --git a/src/python/grpcio/grpc/_channel.py b/src/python/grpcio/grpc/_channel.py index 41e9163cd66..e8c6a99cb18 100644 --- a/src/python/grpcio/grpc/_channel.py +++ b/src/python/grpcio/grpc/_channel.py @@ -32,6 +32,7 @@ import sys import threading import time +import logging import grpc from grpc import _common @@ -197,7 +198,16 @@ def _consume_request_iterator( event_handler = _event_handler(state, call, None) def consume_request_iterator(): - for request in request_iterator: + while True: + try: + request = next(request_iterator) + except StopIteration: + break + except Exception as e: + logging.exception("Exception iterating requests!") + call.cancel() + _abort(state, grpc.StatusCode.UNKNOWN, "Exception iterating requests!") + return serialized_request = _common.serialize(request, request_serializer) with state.condition: if state.code is None and not state.cancelled: diff --git a/src/python/grpcio_tests/tests/reflection/_reflection_servicer_test.py b/src/python/grpcio_tests/tests/reflection/_reflection_servicer_test.py index c7bfeaeb959..43d6c971b52 100644 --- a/src/python/grpcio_tests/tests/reflection/_reflection_servicer_test.py +++ b/src/python/grpcio_tests/tests/reflection/_reflection_servicer_test.py @@ -75,7 +75,7 @@ class ReflectionServicerTest(unittest.TestCase): file_by_filename='i-donut-exist' ), ) - responses = tuple(self._stub.ServerReflectionInfo(requests)) + responses = tuple(self._stub.ServerReflectionInfo(iter(requests))) expected_responses = ( reflection_pb2.ServerReflectionResponse( valid_host='', @@ -93,7 +93,7 @@ class ReflectionServicerTest(unittest.TestCase): ) ), ) - self.assertEqual(expected_responses, responses) + self.assertSequenceEqual(expected_responses, responses) def testFileBySymbol(self): requests = ( @@ -104,7 +104,7 @@ class ReflectionServicerTest(unittest.TestCase): file_containing_symbol='i.donut.exist.co.uk.org.net.me.name.foo' ), ) - responses = tuple(self._stub.ServerReflectionInfo(requests)) + responses = tuple(self._stub.ServerReflectionInfo(iter(requests))) expected_responses = ( reflection_pb2.ServerReflectionResponse( valid_host='', @@ -122,7 +122,7 @@ class ReflectionServicerTest(unittest.TestCase): ) ), ) - self.assertEqual(expected_responses, responses) + self.assertSequenceEqual(expected_responses, responses) @unittest.skip('TODO(atash): implement file-containing-extension reflection ' '(see https://github.com/google/protobuf/issues/2248)') @@ -141,7 +141,7 @@ class ReflectionServicerTest(unittest.TestCase): ), ), ) - responses = tuple(self._stub.ServerReflectionInfo(requests)) + responses = tuple(self._stub.ServerReflectionInfo(iter(requests))) expected_responses = ( reflection_pb2.ServerReflectionResponse( valid_host='', @@ -159,7 +159,7 @@ class ReflectionServicerTest(unittest.TestCase): ) ), ) - self.assertEqual(expected_responses, responses) + self.assertSequenceEqual(expected_responses, responses) def testListServices(self): requests = ( @@ -167,7 +167,7 @@ class ReflectionServicerTest(unittest.TestCase): list_services='', ), ) - responses = tuple(self._stub.ServerReflectionInfo(requests)) + responses = tuple(self._stub.ServerReflectionInfo(iter(requests))) expected_responses = ( reflection_pb2.ServerReflectionResponse( valid_host='', @@ -179,7 +179,7 @@ class ReflectionServicerTest(unittest.TestCase): ) ), ) - self.assertEqual(expected_responses, responses) + self.assertSequenceEqual(expected_responses, responses) if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/src/python/grpcio_tests/tests/tests.json b/src/python/grpcio_tests/tests/tests.json index 0109ee2173d..70d965d3ca8 100644 --- a/src/python/grpcio_tests/tests/tests.json +++ b/src/python/grpcio_tests/tests/tests.json @@ -28,6 +28,7 @@ "unit._empty_message_test.EmptyMessageTest", "unit._exit_test.ExitTest", "unit._invalid_metadata_test.InvalidMetadataTest", + "unit._invocation_defects_test.InvocationDefectsTest", "unit._metadata_code_details_test.MetadataCodeDetailsTest", "unit._metadata_test.MetadataTest", "unit._rpc_test.RPCTest", diff --git a/src/python/grpcio_tests/tests/unit/_compression_test.py b/src/python/grpcio_tests/tests/unit/_compression_test.py index 83b91094666..4d3f02e9175 100644 --- a/src/python/grpcio_tests/tests/unit/_compression_test.py +++ b/src/python/grpcio_tests/tests/unit/_compression_test.py @@ -125,7 +125,7 @@ class CompressionTest(unittest.TestCase): compressed_channel = grpc.insecure_channel('localhost:%d' % self._port, options=[('grpc.default_compression_algorithm', 1)]) multi_callable = compressed_channel.stream_stream(_STREAM_STREAM) - call = multi_callable([request] * test_constants.STREAM_LENGTH) + call = multi_callable(iter([request] * test_constants.STREAM_LENGTH)) for response in call: self.assertEqual(request, response) diff --git a/src/python/grpcio_tests/tests/unit/_empty_message_test.py b/src/python/grpcio_tests/tests/unit/_empty_message_test.py index 131f6e94525..69f46892790 100644 --- a/src/python/grpcio_tests/tests/unit/_empty_message_test.py +++ b/src/python/grpcio_tests/tests/unit/_empty_message_test.py @@ -123,12 +123,12 @@ class EmptyMessageTest(unittest.TestCase): def testStreamUnary(self): response = self._channel.stream_unary(_STREAM_UNARY)( - [_REQUEST] * test_constants.STREAM_LENGTH) + iter([_REQUEST] * test_constants.STREAM_LENGTH)) self.assertEqual(_RESPONSE, response) def testStreamStream(self): response_iterator = self._channel.stream_stream(_STREAM_STREAM)( - [_REQUEST] * test_constants.STREAM_LENGTH) + iter([_REQUEST] * test_constants.STREAM_LENGTH)) self.assertSequenceEqual( [_RESPONSE] * test_constants.STREAM_LENGTH, list(response_iterator)) diff --git a/src/python/grpcio_tests/tests/unit/_exit_scenarios.py b/src/python/grpcio_tests/tests/unit/_exit_scenarios.py index b33802bf572..777527137f0 100644 --- a/src/python/grpcio_tests/tests/unit/_exit_scenarios.py +++ b/src/python/grpcio_tests/tests/unit/_exit_scenarios.py @@ -240,7 +240,7 @@ if __name__ == '__main__': multi_callable = channel.stream_unary(method) future = multi_callable.future(infinite_request_iterator()) result, call = multi_callable.with_call( - [REQUEST] * test_constants.STREAM_LENGTH) + iter([REQUEST] * test_constants.STREAM_LENGTH)) elif (args.scenario == IN_FLIGHT_STREAM_STREAM_CALL or args.scenario == IN_FLIGHT_PARTIAL_STREAM_STREAM_CALL): multi_callable = channel.stream_stream(method) diff --git a/src/python/grpcio_tests/tests/unit/_invocation_defects_test.py b/src/python/grpcio_tests/tests/unit/_invocation_defects_test.py new file mode 100644 index 00000000000..4312679bb96 --- /dev/null +++ b/src/python/grpcio_tests/tests/unit/_invocation_defects_test.py @@ -0,0 +1,247 @@ +# Copyright 2016, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +import itertools +import threading +import unittest +from concurrent import futures + +import grpc +from grpc.framework.foundation import logging_pool + +from tests.unit.framework.common import test_constants +from tests.unit.framework.common import test_control + +_SERIALIZE_REQUEST = lambda bytestring: bytestring * 2 +_DESERIALIZE_REQUEST = lambda bytestring: bytestring[len(bytestring) // 2:] +_SERIALIZE_RESPONSE = lambda bytestring: bytestring * 3 +_DESERIALIZE_RESPONSE = lambda bytestring: bytestring[:len(bytestring) // 3] + +_UNARY_UNARY = '/test/UnaryUnary' +_UNARY_STREAM = '/test/UnaryStream' +_STREAM_UNARY = '/test/StreamUnary' +_STREAM_STREAM = '/test/StreamStream' + + +class _Callback(object): + def __init__(self): + self._condition = threading.Condition() + self._value = None + self._called = False + + def __call__(self, value): + with self._condition: + self._value = value + self._called = True + self._condition.notify_all() + + def value(self): + with self._condition: + while not self._called: + self._condition.wait() + return self._value + + +class _Handler(object): + def __init__(self, control): + self._control = control + + def handle_unary_unary(self, request, servicer_context): + self._control.control() + if servicer_context is not None: + servicer_context.set_trailing_metadata((('testkey', 'testvalue',),)) + return request + + def handle_unary_stream(self, request, servicer_context): + for _ in range(test_constants.STREAM_LENGTH): + self._control.control() + yield request + self._control.control() + if servicer_context is not None: + servicer_context.set_trailing_metadata((('testkey', 'testvalue',),)) + + def handle_stream_unary(self, request_iterator, servicer_context): + if servicer_context is not None: + servicer_context.invocation_metadata() + self._control.control() + response_elements = [] + for request in request_iterator: + self._control.control() + response_elements.append(request) + self._control.control() + if servicer_context is not None: + servicer_context.set_trailing_metadata((('testkey', 'testvalue',),)) + return b''.join(response_elements) + + def handle_stream_stream(self, request_iterator, servicer_context): + self._control.control() + if servicer_context is not None: + servicer_context.set_trailing_metadata((('testkey', 'testvalue',),)) + for request in request_iterator: + self._control.control() + yield request + self._control.control() + + +class _MethodHandler(grpc.RpcMethodHandler): + def __init__( + self, request_streaming, response_streaming, request_deserializer, + response_serializer, unary_unary, unary_stream, stream_unary, + stream_stream): + self.request_streaming = request_streaming + self.response_streaming = response_streaming + self.request_deserializer = request_deserializer + self.response_serializer = response_serializer + self.unary_unary = unary_unary + self.unary_stream = unary_stream + self.stream_unary = stream_unary + self.stream_stream = stream_stream + + +class _GenericHandler(grpc.GenericRpcHandler): + def __init__(self, handler): + self._handler = handler + + def service(self, handler_call_details): + if handler_call_details.method == _UNARY_UNARY: + return _MethodHandler( + False, False, None, None, self._handler.handle_unary_unary, None, + None, None) + elif handler_call_details.method == _UNARY_STREAM: + return _MethodHandler( + False, True, _DESERIALIZE_REQUEST, _SERIALIZE_RESPONSE, None, + self._handler.handle_unary_stream, None, None) + elif handler_call_details.method == _STREAM_UNARY: + return _MethodHandler( + True, False, _DESERIALIZE_REQUEST, _SERIALIZE_RESPONSE, None, None, + self._handler.handle_stream_unary, None) + elif handler_call_details.method == _STREAM_STREAM: + return _MethodHandler( + True, True, None, None, None, None, None, + self._handler.handle_stream_stream) + else: + return None + + +class FailAfterFewIterationsCounter(object): + def __init__(self, high, bytestring): + self._current = 0 + self._high = high + self._bytestring = bytestring + + def __iter__(self): + return self + + def __next__(self): + if self._current >= self._high: + raise Exception("This is a deliberate failure in a unit test.") + else: + self._current += 1 + return self._bytestring + + +def _unary_unary_multi_callable(channel): + return channel.unary_unary(_UNARY_UNARY) + + +def _unary_stream_multi_callable(channel): + return channel.unary_stream( + _UNARY_STREAM, + request_serializer=_SERIALIZE_REQUEST, + response_deserializer=_DESERIALIZE_RESPONSE) + + +def _stream_unary_multi_callable(channel): + return channel.stream_unary( + _STREAM_UNARY, + request_serializer=_SERIALIZE_REQUEST, + response_deserializer=_DESERIALIZE_RESPONSE) + + +def _stream_stream_multi_callable(channel): + return channel.stream_stream(_STREAM_STREAM) + + +class InvocationDefectsTest(unittest.TestCase): + def setUp(self): + self._control = test_control.PauseFailControl() + self._handler = _Handler(self._control) + self._server_pool = logging_pool.pool(test_constants.THREAD_CONCURRENCY) + + self._server = grpc.server(self._server_pool) + port = self._server.add_insecure_port('[::]:0') + self._server.add_generic_rpc_handlers((_GenericHandler(self._handler),)) + self._server.start() + + self._channel = grpc.insecure_channel('localhost:%d' % port) + + def tearDown(self): + self._server.stop(0) + + def testIterableStreamRequestBlockingUnaryResponse(self): + requests = [b'\x07\x08' for _ in range(test_constants.STREAM_LENGTH)] + multi_callable = _stream_unary_multi_callable(self._channel) + + with self.assertRaises(grpc.RpcError): + response = multi_callable( + requests, + metadata=(('test', 'IterableStreamRequestBlockingUnaryResponse'),)) + + def testIterableStreamRequestFutureUnaryResponse(self): + requests = [b'\x07\x08' for _ in range(test_constants.STREAM_LENGTH)] + multi_callable = _stream_unary_multi_callable(self._channel) + response_future = multi_callable.future( + requests, + metadata=( + ('test', 'IterableStreamRequestFutureUnaryResponse'),)) + + with self.assertRaises(grpc.RpcError): + response = response_future.result() + + def testIterableStreamRequestStreamResponse(self): + requests = [b'\x77\x58' for _ in range(test_constants.STREAM_LENGTH)] + multi_callable = _stream_stream_multi_callable(self._channel) + response_iterator = multi_callable( + requests, + metadata=(('test', 'IterableStreamRequestStreamResponse'),)) + + with self.assertRaises(grpc.RpcError): + next(response_iterator) + + def testIteratorStreamRequestStreamResponse(self): + requests_iterator = FailAfterFewIterationsCounter( + test_constants.STREAM_LENGTH // 2, b'\x07\x08') + multi_callable = _stream_stream_multi_callable(self._channel) + response_iterator = multi_callable( + requests_iterator, + metadata=(('test', 'IteratorStreamRequestStreamResponse'),)) + + with self.assertRaises(grpc.RpcError): + for _ in range(test_constants.STREAM_LENGTH // 2 + 1): + next(response_iterator) diff --git a/src/python/grpcio_tests/tests/unit/_metadata_test.py b/src/python/grpcio_tests/tests/unit/_metadata_test.py index da734769299..caba53ffcc9 100644 --- a/src/python/grpcio_tests/tests/unit/_metadata_test.py +++ b/src/python/grpcio_tests/tests/unit/_metadata_test.py @@ -193,7 +193,7 @@ class MetadataTest(unittest.TestCase): def testStreamUnary(self): multi_callable = self._channel.stream_unary(_STREAM_UNARY) unused_response, call = multi_callable.with_call( - [_REQUEST] * test_constants.STREAM_LENGTH, + iter([_REQUEST] * test_constants.STREAM_LENGTH), metadata=_CLIENT_METADATA) self.assertTrue(test_common.metadata_transmitted( _SERVER_INITIAL_METADATA, call.initial_metadata())) @@ -202,7 +202,7 @@ class MetadataTest(unittest.TestCase): def testStreamStream(self): multi_callable = self._channel.stream_stream(_STREAM_STREAM) - call = multi_callable([_REQUEST] * test_constants.STREAM_LENGTH, + call = multi_callable(iter([_REQUEST] * test_constants.STREAM_LENGTH), metadata=_CLIENT_METADATA) self.assertTrue(test_common.metadata_transmitted( _SERVER_INITIAL_METADATA, call.initial_metadata())) diff --git a/templates/tools/doxygen/Doxyfile.include b/templates/tools/doxygen/Doxyfile.include index 8b0c528c1f6..a22f07f33fb 100644 --- a/templates/tools/doxygen/Doxyfile.include +++ b/templates/tools/doxygen/Doxyfile.include @@ -8,7 +8,10 @@ <%def name="gen_doxyfile(libnames, packagename, collection, internal)"> <% import itertools + import glob + import os targets = [] + docpackage = packagename.replace('+', 'p').lower() for libname in libnames: target = None for p in collection: @@ -16,6 +19,11 @@ target = p assert(target) targets.append(target) + srcdoc = [] + for dirpath, dirnames, filenames in os.walk('src/%s' % docpackage): + for filename in filenames: + if os.path.splitext(filename)[1] == '.md': + srcdoc.append(os.path.join(dirpath, filename)) %> # Doxyfile 1.8.9.1 @@ -778,13 +786,20 @@ WARN_LOGFILE = # spaces. # Note: If this tag is empty the current directory is searched. -INPUT = ${' \\\n'.join( - itertools.chain.from_iterable( - target.public_headers + - ([] - if not internal - else target.headers + target.src) - for target in targets))} +INPUT = ${ + ' \\\n'.join( + itertools.chain( + itertools.chain.from_iterable( + target.public_headers + + ([] + if not internal + else target.headers + target.src) + for target in targets), + glob.glob('doc/*.md'), + glob.glob('doc/%s/*.md' % docpackage), + [] if not internal else srcdoc) + ) +} # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses diff --git a/test/core/end2end/fuzzers/api_fuzzer.c b/test/core/end2end/fuzzers/api_fuzzer.c index 6c7cbadea33..200a51858a0 100644 --- a/test/core/end2end/fuzzers/api_fuzzer.c +++ b/test/core/end2end/fuzzers/api_fuzzer.c @@ -369,10 +369,11 @@ void my_resolve_address(grpc_exec_ctx *exec_ctx, const char *addr, r->addr = gpr_strdup(addr); r->on_done = on_done; r->addrs = addresses; - grpc_timer_init(exec_ctx, &r->timer, - gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), - gpr_time_from_seconds(1, GPR_TIMESPAN)), - finish_resolve, r, gpr_now(GPR_CLOCK_MONOTONIC)); + grpc_timer_init( + exec_ctx, &r->timer, gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), + gpr_time_from_seconds(1, GPR_TIMESPAN)), + grpc_closure_create(finish_resolve, r, grpc_schedule_on_exec_ctx), + gpr_now(GPR_CLOCK_MONOTONIC)); } //////////////////////////////////////////////////////////////////////////////// @@ -430,10 +431,11 @@ static void sched_connect(grpc_exec_ctx *exec_ctx, grpc_closure *closure, fc->closure = closure; fc->ep = ep; fc->deadline = deadline; - grpc_timer_init(exec_ctx, &fc->timer, - gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), - gpr_time_from_millis(1, GPR_TIMESPAN)), - do_connect, fc, gpr_now(GPR_CLOCK_MONOTONIC)); + grpc_timer_init( + exec_ctx, &fc->timer, gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), + gpr_time_from_millis(1, GPR_TIMESPAN)), + grpc_closure_create(do_connect, fc, grpc_schedule_on_exec_ctx), + gpr_now(GPR_CLOCK_MONOTONIC)); } static void my_tcp_client_connect(grpc_exec_ctx *exec_ctx, diff --git a/test/core/iomgr/timer_list_test.c b/test/core/iomgr/timer_list_test.c index be8988ab752..8d7ac3fdaa1 100644 --- a/test/core/iomgr/timer_list_test.c +++ b/test/core/iomgr/timer_list_test.c @@ -57,17 +57,20 @@ static void add_test(void) { /* 10 ms timers. will expire in the current epoch */ for (i = 0; i < 10; i++) { - grpc_timer_init(&exec_ctx, &timers[i], - gpr_time_add(start, gpr_time_from_millis(10, GPR_TIMESPAN)), - cb, (void *)(intptr_t)i, start); + grpc_timer_init( + &exec_ctx, &timers[i], + gpr_time_add(start, gpr_time_from_millis(10, GPR_TIMESPAN)), + grpc_closure_create(cb, (void *)(intptr_t)i, grpc_schedule_on_exec_ctx), + start); } /* 1010 ms timers. will expire in the next epoch */ for (i = 10; i < 20; i++) { grpc_timer_init( &exec_ctx, &timers[i], - gpr_time_add(start, gpr_time_from_millis(1010, GPR_TIMESPAN)), cb, - (void *)(intptr_t)i, start); + gpr_time_add(start, gpr_time_from_millis(1010, GPR_TIMESPAN)), + grpc_closure_create(cb, (void *)(intptr_t)i, grpc_schedule_on_exec_ctx), + start); } /* collect timers. Only the first batch should be ready. */ @@ -125,16 +128,26 @@ void destruction_test(void) { grpc_timer_list_init(gpr_time_0(GPR_CLOCK_REALTIME)); memset(cb_called, 0, sizeof(cb_called)); - grpc_timer_init(&exec_ctx, &timers[0], tfm(100), cb, (void *)(intptr_t)0, - gpr_time_0(GPR_CLOCK_REALTIME)); - grpc_timer_init(&exec_ctx, &timers[1], tfm(3), cb, (void *)(intptr_t)1, - gpr_time_0(GPR_CLOCK_REALTIME)); - grpc_timer_init(&exec_ctx, &timers[2], tfm(100), cb, (void *)(intptr_t)2, - gpr_time_0(GPR_CLOCK_REALTIME)); - grpc_timer_init(&exec_ctx, &timers[3], tfm(3), cb, (void *)(intptr_t)3, - gpr_time_0(GPR_CLOCK_REALTIME)); - grpc_timer_init(&exec_ctx, &timers[4], tfm(1), cb, (void *)(intptr_t)4, - gpr_time_0(GPR_CLOCK_REALTIME)); + grpc_timer_init( + &exec_ctx, &timers[0], tfm(100), + grpc_closure_create(cb, (void *)(intptr_t)0, grpc_schedule_on_exec_ctx), + gpr_time_0(GPR_CLOCK_REALTIME)); + grpc_timer_init( + &exec_ctx, &timers[1], tfm(3), + grpc_closure_create(cb, (void *)(intptr_t)1, grpc_schedule_on_exec_ctx), + gpr_time_0(GPR_CLOCK_REALTIME)); + grpc_timer_init( + &exec_ctx, &timers[2], tfm(100), + grpc_closure_create(cb, (void *)(intptr_t)2, grpc_schedule_on_exec_ctx), + gpr_time_0(GPR_CLOCK_REALTIME)); + grpc_timer_init( + &exec_ctx, &timers[3], tfm(3), + grpc_closure_create(cb, (void *)(intptr_t)3, grpc_schedule_on_exec_ctx), + gpr_time_0(GPR_CLOCK_REALTIME)); + grpc_timer_init( + &exec_ctx, &timers[4], tfm(1), + grpc_closure_create(cb, (void *)(intptr_t)4, grpc_schedule_on_exec_ctx), + gpr_time_0(GPR_CLOCK_REALTIME)); GPR_ASSERT(1 == grpc_timer_check(&exec_ctx, tfm(2), NULL)); grpc_exec_ctx_finish(&exec_ctx); GPR_ASSERT(1 == cb_called[4][1]); diff --git a/tools/doxygen/Doxyfile.c++ b/tools/doxygen/Doxyfile.c++ index bf4cb57ae3b..2cd59863b62 100644 --- a/tools/doxygen/Doxyfile.c++ +++ b/tools/doxygen/Doxyfile.c++ @@ -848,7 +848,35 @@ include/grpc/impl/codegen/slice.h \ include/grpc/impl/codegen/sync.h \ include/grpc/impl/codegen/sync_generic.h \ include/grpc/impl/codegen/sync_posix.h \ -include/grpc/impl/codegen/sync_windows.h +include/grpc/impl/codegen/sync_windows.h \ +doc/fail_fast.md \ +doc/compression.md \ +doc/environment_variables.md \ +doc/stress_test_framework.md \ +doc/PROTOCOL-WEB.md \ +doc/cpp-style-guide.md \ +doc/http-grpc-status-mapping.md \ +doc/wait-for-ready.md \ +doc/command_line_tool.md \ +doc/c-style-guide.md \ +doc/server_reflection_tutorial.md \ +doc/health-checking.md \ +doc/connection-backoff-interop-test-description.md \ +doc/epoll-polling-engine.md \ +doc/naming.md \ +doc/binary-logging.md \ +doc/connectivity-semantics-and-api.md \ +doc/connection-backoff.md \ +doc/compression_cookbook.md \ +doc/PROTOCOL-HTTP2.md \ +doc/load-balancing.md \ +doc/negative-http2-interop-test-descriptions.md \ +doc/server-reflection.md \ +doc/interop-test-descriptions.md \ +doc/statuscodes.md \ +doc/g_stands_for.md \ +doc/cpp/perf_notes.md \ +doc/cpp/pending_api_cleanups.md # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal index 1ab5f4933e8..6ab452eaba9 100644 --- a/tools/doxygen/Doxyfile.c++.internal +++ b/tools/doxygen/Doxyfile.c++.internal @@ -894,7 +894,36 @@ src/cpp/util/slice_cc.cc \ src/cpp/util/status.cc \ src/cpp/util/string_ref.cc \ src/cpp/util/time_cc.cc \ -src/cpp/codegen/codegen_init.cc +src/cpp/codegen/codegen_init.cc \ +doc/fail_fast.md \ +doc/compression.md \ +doc/environment_variables.md \ +doc/stress_test_framework.md \ +doc/PROTOCOL-WEB.md \ +doc/cpp-style-guide.md \ +doc/http-grpc-status-mapping.md \ +doc/wait-for-ready.md \ +doc/command_line_tool.md \ +doc/c-style-guide.md \ +doc/server_reflection_tutorial.md \ +doc/health-checking.md \ +doc/connection-backoff-interop-test-description.md \ +doc/epoll-polling-engine.md \ +doc/naming.md \ +doc/binary-logging.md \ +doc/connectivity-semantics-and-api.md \ +doc/connection-backoff.md \ +doc/compression_cookbook.md \ +doc/PROTOCOL-HTTP2.md \ +doc/load-balancing.md \ +doc/negative-http2-interop-test-descriptions.md \ +doc/server-reflection.md \ +doc/interop-test-descriptions.md \ +doc/statuscodes.md \ +doc/g_stands_for.md \ +doc/cpp/perf_notes.md \ +doc/cpp/pending_api_cleanups.md \ +src/cpp/README.md # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses diff --git a/tools/doxygen/Doxyfile.core b/tools/doxygen/Doxyfile.core index af9c00a8ad6..16f8dcc29e5 100644 --- a/tools/doxygen/Doxyfile.core +++ b/tools/doxygen/Doxyfile.core @@ -827,7 +827,34 @@ include/grpc/impl/codegen/slice.h \ include/grpc/impl/codegen/sync.h \ include/grpc/impl/codegen/sync_generic.h \ include/grpc/impl/codegen/sync_posix.h \ -include/grpc/impl/codegen/sync_windows.h +include/grpc/impl/codegen/sync_windows.h \ +doc/fail_fast.md \ +doc/compression.md \ +doc/environment_variables.md \ +doc/stress_test_framework.md \ +doc/PROTOCOL-WEB.md \ +doc/cpp-style-guide.md \ +doc/http-grpc-status-mapping.md \ +doc/wait-for-ready.md \ +doc/command_line_tool.md \ +doc/c-style-guide.md \ +doc/server_reflection_tutorial.md \ +doc/health-checking.md \ +doc/connection-backoff-interop-test-description.md \ +doc/epoll-polling-engine.md \ +doc/naming.md \ +doc/binary-logging.md \ +doc/connectivity-semantics-and-api.md \ +doc/connection-backoff.md \ +doc/compression_cookbook.md \ +doc/PROTOCOL-HTTP2.md \ +doc/load-balancing.md \ +doc/negative-http2-interop-test-descriptions.md \ +doc/server-reflection.md \ +doc/interop-test-descriptions.md \ +doc/statuscodes.md \ +doc/g_stands_for.md \ +doc/core/pending_api_cleanups.md # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal index 13919245e4d..d9f69427b1b 100644 --- a/tools/doxygen/Doxyfile.core.internal +++ b/tools/doxygen/Doxyfile.core.internal @@ -1278,7 +1278,55 @@ src/core/lib/support/tls_pthread.c \ src/core/lib/support/tmpfile_msys.c \ src/core/lib/support/tmpfile_posix.c \ src/core/lib/support/tmpfile_windows.c \ -src/core/lib/support/wrap_memcpy.c +src/core/lib/support/wrap_memcpy.c \ +doc/fail_fast.md \ +doc/compression.md \ +doc/environment_variables.md \ +doc/stress_test_framework.md \ +doc/PROTOCOL-WEB.md \ +doc/cpp-style-guide.md \ +doc/http-grpc-status-mapping.md \ +doc/wait-for-ready.md \ +doc/command_line_tool.md \ +doc/c-style-guide.md \ +doc/server_reflection_tutorial.md \ +doc/health-checking.md \ +doc/connection-backoff-interop-test-description.md \ +doc/epoll-polling-engine.md \ +doc/naming.md \ +doc/binary-logging.md \ +doc/connectivity-semantics-and-api.md \ +doc/connection-backoff.md \ +doc/compression_cookbook.md \ +doc/PROTOCOL-HTTP2.md \ +doc/load-balancing.md \ +doc/negative-http2-interop-test-descriptions.md \ +doc/server-reflection.md \ +doc/interop-test-descriptions.md \ +doc/statuscodes.md \ +doc/g_stands_for.md \ +doc/core/pending_api_cleanups.md \ +src/core/README.md \ +src/core/ext/README.md \ +src/core/ext/transport/README.md \ +src/core/ext/transport/chttp2/README.md \ +src/core/ext/transport/chttp2/client/secure/README.md \ +src/core/ext/transport/chttp2/client/insecure/README.md \ +src/core/ext/transport/chttp2/transport/README.md \ +src/core/ext/transport/chttp2/server/secure/README.md \ +src/core/ext/transport/chttp2/server/insecure/README.md \ +src/core/ext/client_channel/README.md \ +src/core/ext/resolver/README.md \ +src/core/ext/resolver/sockaddr/README.md \ +src/core/ext/resolver/dns/native/README.md \ +src/core/ext/census/README.md \ +src/core/ext/census/gen/README.md \ +src/core/lib/README.md \ +src/core/lib/tsi/README.md \ +src/core/lib/channel/README.md \ +src/core/lib/transport/README.md \ +src/core/lib/iomgr/README.md \ +src/core/lib/surface/README.md # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses diff --git a/tools/run_tests/README.md b/tools/run_tests/README.md index dd727f43091..e709ddd2c02 100644 --- a/tools/run_tests/README.md +++ b/tools/run_tests/README.md @@ -22,6 +22,10 @@ The script is also capable of running interop tests for grpc-java and grpc-go, u ######Example `tools/run_tests/run_interop_tests.py -l csharp -s c++ --use_docker` (run interop tests with C# client and C++ server) +Note: if you see an error like `no space left on device` when running the +interop tests using Docker, make sure that Docker is building the image files in +a location with sufficient disk space. + #Performance benchmarks (run_performance_tests.py) Runs predefined benchmark scenarios for given languages. Besides the simple configuration of running all the scenarios locally, diff --git a/tools/run_tests/run_interop_tests.py b/tools/run_tests/run_interop_tests.py index c14f18af818..981e38b813d 100755 --- a/tools/run_tests/run_interop_tests.py +++ b/tools/run_tests/run_interop_tests.py @@ -179,10 +179,10 @@ class JavaLanguage: return {} def unimplemented_test_cases(self): - return _SKIP_ADVANCED + _SKIP_COMPRESSION + return _SKIP_COMPRESSION def unimplemented_test_cases_server(self): - return _SKIP_ADVANCED + _SKIP_COMPRESSION + return _SKIP_COMPRESSION def __str__(self): return 'java' diff --git a/vsprojects/README.md b/vsprojects/README.md index 7af69c2726b..afd6430bfe5 100644 --- a/vsprojects/README.md +++ b/vsprojects/README.md @@ -2,7 +2,7 @@ This directory contains MS Visual Studio project & solution files. #Supported Visual Studio versions -Currently supported versions are Visual Studio 2013 (our primary focus) and 2010. +Currently supported versions are Visual Studio 2013 (our primary focus). #Building We are using [NuGet](http://www.nuget.org) to pull zlib and openssl dependencies. diff --git a/vsprojects/build_vs2010.bat b/vsprojects/build_vs2010.bat deleted file mode 100644 index d9512953696..00000000000 --- a/vsprojects/build_vs2010.bat +++ /dev/null @@ -1,39 +0,0 @@ -@rem Copyright 2016, Google Inc. -@rem All rights reserved. -@rem -@rem Redistribution and use in source and binary forms, with or without -@rem modification, are permitted provided that the following conditions are -@rem met: -@rem -@rem * Redistributions of source code must retain the above copyright -@rem notice, this list of conditions and the following disclaimer. -@rem * Redistributions in binary form must reproduce the above -@rem copyright notice, this list of conditions and the following disclaimer -@rem in the documentation and/or other materials provided with the -@rem distribution. -@rem * Neither the name of Google Inc. nor the names of its -@rem contributors may be used to endorse or promote products derived from -@rem this software without specific prior written permission. -@rem -@rem THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -@rem "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -@rem LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -@rem A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -@rem OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -@rem SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -@rem LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -@rem DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -@rem THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -@rem (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -@rem OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -@rem Convenience wrapper that runs specified gRPC target using msbuild -@rem Usage: build_vs2010.bat TARGET_NAME - -setlocal -@rem Set VS variables (uses Visual Studio 2010) -@call "%VS100COMNTOOLS%\..\..\vc\vcvarsall.bat" x86 - -msbuild %* -exit /b %ERRORLEVEL% -endlocal diff --git a/vsprojects/coapp/zlib/README.md b/vsprojects/coapp/zlib/README.md index d62e9030ed7..e9a89c030ee 100644 --- a/vsprojects/coapp/zlib/README.md +++ b/vsprojects/coapp/zlib/README.md @@ -10,7 +10,7 @@ Multiple versions of VS installed to be able to build all the targets: * Visual Studio 2013 * Visual Studio 2010 (you might need SP1 to prevent LNK1123 error) -CoApp toolkit: http://downloads.coapp.org/files/CoApp.Tools.Powershell.msi +CoApp toolkit: http://coapp.org/files/CoApp.Tools.Powershell.msi More details on installation: http://coapp.org/tutorials/installation.html @@ -33,4 +33,4 @@ This will create three NuGet packages: * the symbols package (debug symbols) Later, you can push the package to NuGet.org repo. -Attention: before pusing the resulting nuget package to public nuget repo, you have to be 100% sure it works correctly - there’s no way how to delete or update an already existing package. \ No newline at end of file +Attention: before pusing the resulting nuget package to public nuget repo, you have to be 100% sure it works correctly - there’s no way how to delete or update an already existing package.