Merge pull request #2286 from ctiller/split-me-baby-one-more-time

Further lock contention reduction for CHTTP2
pull/6357/head
Jan Tattermusch 9 years ago
commit 0d6fee6c8e
  1. 4
      src/core/ext/census/grpc_filter.c
  2. 5
      src/core/ext/client_config/client_channel.c
  3. 6
      src/core/ext/client_config/subchannel.c
  4. 657
      src/core/ext/transport/chttp2/transport/chttp2_transport.c
  5. 63
      src/core/ext/transport/chttp2/transport/internal.h
  6. 8
      src/core/ext/transport/chttp2/transport/stream_lists.c
  7. 6
      src/core/lib/channel/channel_stack.c
  8. 11
      src/core/lib/channel/channel_stack.h
  9. 4
      src/core/lib/channel/compress_filter.c
  10. 7
      src/core/lib/channel/connected_channel.c
  11. 4
      src/core/lib/channel/http_client_filter.c
  12. 4
      src/core/lib/channel/http_server_filter.c
  13. 6
      src/core/lib/iomgr/iomgr.c
  14. 4
      src/core/lib/security/client_auth_filter.c
  15. 4
      src/core/lib/security/server_auth_filter.c
  16. 6
      src/core/lib/surface/call.c
  17. 4
      src/core/lib/surface/completion_queue.c
  18. 6
      src/core/lib/surface/lame_client.c
  19. 4
      src/core/lib/surface/server.c
  20. 5
      src/core/lib/transport/transport.c
  21. 12
      src/core/lib/transport/transport.h
  22. 2
      src/core/lib/transport/transport_impl.h
  23. 6
      test/core/channel/channel_stack_test.c
  24. 4
      test/core/end2end/tests/filter_causes_close.c

@ -134,7 +134,7 @@ static void client_init_call_elem(grpc_exec_ctx *exec_ctx,
}
static void client_destroy_call_elem(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem) {
grpc_call_element *elem, void *ignored) {
call_data *d = elem->call_data;
GPR_ASSERT(d != NULL);
/* TODO(hongyu): record rpc client stats and census_rpc_end_op here */
@ -152,7 +152,7 @@ static void server_init_call_elem(grpc_exec_ctx *exec_ctx,
}
static void server_destroy_call_elem(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem) {
grpc_call_element *elem, void *ignored) {
call_data *d = elem->call_data;
GPR_ASSERT(d != NULL);
/* TODO(hongyu): record rpc server stats and census_tracing_end_op here */

@ -415,9 +415,10 @@ static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
}
/* Destructor for call_data */
static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem) {
static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
void *and_free_memory) {
grpc_subchannel_call_holder_destroy(exec_ctx, elem->call_data);
gpr_free(and_free_memory);
}
/* Constructor for channel_data */

@ -644,9 +644,9 @@ static void subchannel_call_destroy(grpc_exec_ctx *exec_ctx, void *call,
bool success) {
grpc_subchannel_call *c = call;
GPR_TIMER_BEGIN("grpc_subchannel_call_unref.destroy", 0);
grpc_call_stack_destroy(exec_ctx, SUBCHANNEL_CALL_TO_CALL_STACK(c));
GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, c->connection, "subchannel_call");
gpr_free(c);
grpc_connected_subchannel *connection = c->connection;
grpc_call_stack_destroy(exec_ctx, SUBCHANNEL_CALL_TO_CALL_STACK(c), c);
GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, connection, "subchannel_call");
GPR_TIMER_END("grpc_subchannel_call_unref.destroy", 0);
}

File diff suppressed because it is too large Load Diff

@ -291,27 +291,44 @@ struct grpc_chttp2_transport_parsing {
int64_t outgoing_window;
};
typedef void (*grpc_chttp2_locked_action)(grpc_exec_ctx *ctx,
grpc_chttp2_transport *t,
grpc_chttp2_stream *s, void *arg);
typedef struct grpc_chttp2_executor_action_header {
grpc_chttp2_stream *stream;
grpc_chttp2_locked_action action;
struct grpc_chttp2_executor_action_header *next;
void *arg;
} grpc_chttp2_executor_action_header;
struct grpc_chttp2_transport {
grpc_transport base; /* must be first */
grpc_endpoint *ep;
gpr_refcount refs;
grpc_endpoint *ep;
char *peer_string;
/** when this drops to zero it's safe to shutdown the endpoint */
gpr_refcount shutdown_ep_refs;
struct {
gpr_mu mu;
/** is a thread currently in the global lock */
bool global_active;
/** is a thread currently writing */
bool writing_active;
/** is a thread currently parsing */
bool parsing_active;
grpc_chttp2_executor_action_header *pending_actions;
} executor;
/** is the transport destroying itself? */
uint8_t destroying;
/** has the upper layer closed the transport? */
uint8_t closed;
/** is a thread currently writing */
uint8_t writing_active;
/** is a thread currently parsing */
uint8_t parsing_active;
/** is there a read request to the endpoint outstanding? */
uint8_t endpoint_reading;
@ -338,8 +355,10 @@ struct grpc_chttp2_transport {
/** closure to execute writing */
grpc_closure writing_action;
/** closure to finish reading from the endpoint */
grpc_closure recv_data;
/** closure to start reading from the endpoint */
grpc_closure reading_action;
/** closure to actually do parsing */
grpc_closure parsing_action;
/** incoming read bytes */
gpr_slice_buffer read_buffer;
@ -397,21 +416,26 @@ typedef struct {
grpc_transport_stream_stats *collecting_stats;
grpc_transport_stream_stats stats;
/** number of streams that are currently being read */
gpr_refcount active_streams;
/** when the application requests writes be closed, the write_closed is
'queued'; when the close is flow controlled into the send path, we are
'sending' it; when the write has been performed it is 'sent' */
uint8_t write_closed;
bool write_closed;
/** is this stream reading half-closed (boolean) */
uint8_t read_closed;
bool read_closed;
/** are all published incoming byte streams closed */
bool all_incoming_byte_streams_finished;
/** is this stream in the stream map? (boolean) */
uint8_t in_stream_map;
bool in_stream_map;
/** has this stream seen an error? if 1, then pending incoming frames
can be thrown away */
uint8_t seen_error;
bool seen_error;
uint8_t published_initial_metadata;
uint8_t published_trailing_metadata;
uint8_t faked_trailing_metadata;
bool published_initial_metadata;
bool published_trailing_metadata;
bool faked_trailing_metadata;
grpc_chttp2_incoming_metadata_buffer received_initial_metadata;
grpc_chttp2_incoming_metadata_buffer received_trailing_metadata;
@ -570,6 +594,9 @@ int grpc_chttp2_list_pop_waiting_for_concurrency(
void grpc_chttp2_list_add_check_read_ops(
grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global);
bool grpc_chttp2_list_remove_check_read_ops(
grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global);
int grpc_chttp2_list_pop_check_read_ops(
grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global **stream_global);
@ -645,6 +672,12 @@ void grpc_chttp2_complete_closure_step(grpc_exec_ctx *exec_ctx,
grpc_chttp2_stream_global *stream_global,
grpc_closure **pclosure, int success);
void grpc_chttp2_run_with_global_lock(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *transport,
grpc_chttp2_stream *optional_stream,
grpc_chttp2_locked_action action,
void *arg, size_t sizeof_arg);
#define GRPC_CHTTP2_CLIENT_CONNECT_STRING "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
#define GRPC_CHTTP2_CLIENT_CONNECT_STRLEN \
(sizeof(GRPC_CHTTP2_CLIENT_CONNECT_STRING) - 1)

@ -305,6 +305,14 @@ void grpc_chttp2_list_add_check_read_ops(
GRPC_CHTTP2_LIST_CHECK_READ_OPS);
}
bool grpc_chttp2_list_remove_check_read_ops(
grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global) {
return stream_list_maybe_remove(TRANSPORT_FROM_GLOBAL(transport_global),
STREAM_FROM_GLOBAL(stream_global),
GRPC_CHTTP2_LIST_CHECK_READ_OPS);
}
int grpc_chttp2_list_pop_check_read_ops(
grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global **stream_global) {

@ -213,14 +213,16 @@ void grpc_call_stack_ignore_set_pollset(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem,
grpc_pollset *pollset) {}
void grpc_call_stack_destroy(grpc_exec_ctx *exec_ctx, grpc_call_stack *stack) {
void grpc_call_stack_destroy(grpc_exec_ctx *exec_ctx, grpc_call_stack *stack,
void *and_free_memory) {
grpc_call_element *elems = CALL_ELEMS_FROM_STACK(stack);
size_t count = stack->count;
size_t i;
/* destroy per-filter data */
for (i = 0; i < count; i++) {
elems[i].filter->destroy_call_elem(exec_ctx, &elems[i]);
elems[i].filter->destroy_call_elem(exec_ctx, &elems[i],
i == count - 1 ? and_free_memory : NULL);
}
}

@ -104,8 +104,12 @@ typedef struct {
void (*set_pollset)(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
grpc_pollset *pollset);
/* Destroy per call data.
The filter does not need to do any chaining */
void (*destroy_call_elem)(grpc_exec_ctx *exec_ctx, grpc_call_element *elem);
The filter does not need to do any chaining.
The bottom filter of a stack will be passed a non-NULL pointer to
\a and_free_memory that should be passed to gpr_free when destruction
is complete. */
void (*destroy_call_elem)(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
void *and_free_memory);
/* sizeof(per channel data) */
size_t sizeof_channel_data;
@ -223,7 +227,8 @@ void grpc_call_stack_set_pollset(grpc_exec_ctx *exec_ctx,
#endif
/* Destroy a call stack */
void grpc_call_stack_destroy(grpc_exec_ctx *exec_ctx, grpc_call_stack *stack);
void grpc_call_stack_destroy(grpc_exec_ctx *exec_ctx, grpc_call_stack *stack,
void *and_free_memory);
/* Ignore set pollset - used by filters to implement the set_pollset method
if they don't care about pollsets at all. Does nothing. */

@ -246,8 +246,8 @@ static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
}
/* Destructor for call_data */
static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem) {
static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
void *ignored) {
/* grab pointers to our data from the call element */
call_data *calld = elem->call_data;
gpr_slice_buffer_destroy(&calld->slices);

@ -102,12 +102,13 @@ static void set_pollset(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
}
/* Destructor for call_data */
static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem) {
static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
void *and_free_memory) {
call_data *calld = elem->call_data;
channel_data *chand = elem->channel_data;
grpc_transport_destroy_stream(exec_ctx, chand->transport,
TRANSPORT_STREAM_FROM_CALL_DATA(calld));
TRANSPORT_STREAM_FROM_CALL_DATA(calld),
and_free_memory);
}
/* Constructor for channel_data */

@ -155,8 +155,8 @@ static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
}
/* Destructor for call_data */
static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem) {}
static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
void *ignored) {}
static grpc_mdelem *scheme_from_args(const grpc_channel_args *args) {
unsigned i;

@ -225,8 +225,8 @@ static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
}
/* Destructor for call_data */
static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem) {}
static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
void *ignored) {}
/* Constructor for channel_data */
static void init_channel_elem(grpc_exec_ctx *exec_ctx,

@ -166,8 +166,10 @@ bool grpc_iomgr_abort_on_leaks(void) {
if (env == NULL) return false;
static const char *truthy[] = {"yes", "Yes", "YES", "true",
"True", "TRUE", "1"};
bool should_we = false;
for (size_t i = 0; i < GPR_ARRAY_SIZE(truthy); i++) {
if (0 == strcmp(env, truthy[i])) return true;
if (0 == strcmp(env, truthy[i])) should_we = true;
}
return false;
gpr_free(env);
return should_we;
}

@ -277,8 +277,8 @@ static void set_pollset(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
}
/* Destructor for call_data */
static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem) {
static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
void *ignored) {
call_data *calld = elem->call_data;
grpc_call_credentials_unref(calld->creds);
if (calld->host != NULL) {

@ -224,8 +224,8 @@ static void set_pollset(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
grpc_pollset *pollset) {}
/* Destructor for call_data */
static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem) {}
static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
void *ignored) {}
/* Constructor for channel_data */
static void init_channel_elem(grpc_exec_ctx *exec_ctx,

@ -373,8 +373,6 @@ static void destroy_call(grpc_exec_ctx *exec_ctx, void *call, bool success) {
if (c->receiving_stream != NULL) {
grpc_byte_stream_destroy(exec_ctx, c->receiving_stream);
}
grpc_call_stack_destroy(exec_ctx, CALL_STACK_FROM_CALL(c));
GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, c->channel, "call");
gpr_mu_destroy(&c->mu);
for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
if (c->status[i].details) {
@ -392,7 +390,9 @@ static void destroy_call(grpc_exec_ctx *exec_ctx, void *call, bool success) {
if (c->cq) {
GRPC_CQ_INTERNAL_UNREF(c->cq, "bind");
}
gpr_free(c);
grpc_channel *channel = c->channel;
grpc_call_stack_destroy(exec_ctx, CALL_STACK_FROM_CALL(c), c);
GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, channel, "call");
GPR_TIMER_END("destroy_call", 0);
}

@ -227,6 +227,10 @@ void grpc_cq_end_op(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc,
#endif
GPR_TIMER_BEGIN("grpc_cq_end_op", 0);
GRPC_API_TRACE(
"grpc_cq_end_op(exec_ctx=%p, cc=%p, tag=%p, success=%d, done=%p, "
"done_arg=%p, storage=%p)",
7, (exec_ctx, cc, tag, success, done, done_arg, storage));
storage->tag = tag;
storage->done = done;

@ -107,8 +107,10 @@ static void lame_start_transport_op(grpc_exec_ctx *exec_ctx,
static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
grpc_call_element_args *args) {}
static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem) {}
static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
void *and_free_memory) {
gpr_free(and_free_memory);
}
static void init_channel_elem(grpc_exec_ctx *exec_ctx,
grpc_channel_element *elem,

@ -820,8 +820,8 @@ static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
server_ref(chand->server);
}
static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem) {
static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
void *ignored) {
channel_data *chand = elem->channel_data;
call_data *calld = elem->call_data;

@ -133,8 +133,9 @@ void grpc_transport_set_pollset(grpc_exec_ctx *exec_ctx,
void grpc_transport_destroy_stream(grpc_exec_ctx *exec_ctx,
grpc_transport *transport,
grpc_stream *stream) {
transport->vtable->destroy_stream(exec_ctx, transport, stream);
grpc_stream *stream, void *and_free_memory) {
transport->vtable->destroy_stream(exec_ctx, transport, stream,
and_free_memory);
}
char *grpc_transport_get_peer(grpc_exec_ctx *exec_ctx,

@ -98,6 +98,11 @@ void grpc_transport_move_stats(grpc_transport_stream_stats *from,
/* Transport stream op: a set of operations to perform on a transport
against a single stream */
typedef struct grpc_transport_stream_op {
/** Should be enqueued when all requested operations (excluding recv_message
and recv_initial_metadata which have their own closures) in a given batch
have been completed. */
grpc_closure *on_complete;
/** Send initial metadata to the peer, from the provided metadata batch.
idempotent_request MUST be set if this is non-null */
grpc_metadata_batch *send_initial_metadata;
@ -129,11 +134,6 @@ typedef struct grpc_transport_stream_op {
/** Collect any stats into provided buffer, zero internal stat counters */
grpc_transport_stream_stats *collect_stats;
/** Should be enqueued when all requested operations (excluding recv_message
and recv_initial_metadata which have their own closures) in a given batch
have been completed. */
grpc_closure *on_complete;
/** If != GRPC_STATUS_OK, cancel this stream */
grpc_status_code cancel_with_status;
@ -213,7 +213,7 @@ void grpc_transport_set_pollset(grpc_exec_ctx *exec_ctx,
caller, but any child memory must be cleaned up) */
void grpc_transport_destroy_stream(grpc_exec_ctx *exec_ctx,
grpc_transport *transport,
grpc_stream *stream);
grpc_stream *stream, void *and_free_memory);
void grpc_transport_stream_op_finish_with_failure(grpc_exec_ctx *exec_ctx,
grpc_transport_stream_op *op);

@ -63,7 +63,7 @@ typedef struct grpc_transport_vtable {
/* implementation of grpc_transport_destroy_stream */
void (*destroy_stream)(grpc_exec_ctx *exec_ctx, grpc_transport *self,
grpc_stream *stream);
grpc_stream *stream, void *and_free_memory);
/* implementation of grpc_transport_destroy */
void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_transport *self);

@ -62,8 +62,8 @@ static void call_init_func(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
static void channel_destroy_func(grpc_exec_ctx *exec_ctx,
grpc_channel_element *elem) {}
static void call_destroy_func(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem) {
static void call_destroy_func(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
void *ignored) {
++*(int *)(elem->channel_data);
}
@ -87,7 +87,7 @@ static void free_channel(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
}
static void free_call(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
grpc_call_stack_destroy(exec_ctx, arg);
grpc_call_stack_destroy(exec_ctx, arg, NULL);
gpr_free(arg);
}

@ -232,8 +232,8 @@ static void start_transport_stream_op(grpc_exec_ctx *exec_ctx,
static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
grpc_call_element_args *args) {}
static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem) {}
static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
void *and_free_memory) {}
static void init_channel_elem(grpc_exec_ctx *exec_ctx,
grpc_channel_element *elem,

Loading…
Cancel
Save