/** Compress \a slices in place using \a algorithm. Returns 1 if compression did * actually happen, 0 otherwise (for example if the compressed output size was * larger than the raw input). * * Returns 1 if the data was actually compress and 0 otherwise. */ static int compress_send_sb(grpc_compression_algorithm algorithm, gpr_slice_buffer *slices) { int did_compress; gpr_slice_buffer tmp; gpr_slice_buffer_init(&tmp); did_compress = grpc_msg_compress(algorithm, slices, &tmp); if (did_compress) { gpr_slice_buffer_swap(slices, &tmp); } gpr_slice_buffer_destroy(&tmp); return did_compress; }
void gpr_slice_buffer_move_into(gpr_slice_buffer *src, gpr_slice_buffer *dst) { /* anything to move? */ if (src->count == 0) { return; } /* anything in dst? */ if (dst->count == 0) { gpr_slice_buffer_swap(src, dst); return; } /* both buffers have data - copy, and reset src */ gpr_slice_buffer_addn(dst, src->slices, src->count); src->count = 0; src->length = 0; }
static void tcp_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, gpr_slice_buffer *incoming_buffer, grpc_closure *cb) { grpc_tcp *tcp = (grpc_tcp *)ep; GPR_ASSERT(tcp->read_cb == NULL); tcp->read_cb = cb; tcp->incoming_buffer = incoming_buffer; gpr_slice_buffer_reset_and_unref(incoming_buffer); gpr_slice_buffer_swap(incoming_buffer, &tcp->last_read_buffer); TCP_REF(tcp, "read"); if (tcp->finished_edge) { tcp->finished_edge = 0; grpc_fd_notify_on_read(exec_ctx, tcp->em_fd, &tcp->read_closure); } else { grpc_exec_ctx_enqueue(exec_ctx, &tcp->read_closure, true, NULL); } }
static void endpoint_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *secure_ep, gpr_slice_buffer *slices, grpc_closure *cb) { secure_endpoint *ep = (secure_endpoint *)secure_ep; ep->read_cb = cb; ep->read_buffer = slices; gpr_slice_buffer_reset_and_unref(ep->read_buffer); SECURE_ENDPOINT_REF(ep, "read"); if (ep->leftover_bytes.count) { gpr_slice_buffer_swap(&ep->leftover_bytes, &ep->source_buffer); GPR_ASSERT(ep->leftover_bytes.count == 0); on_read(exec_ctx, ep, GRPC_ERROR_NONE); return; } grpc_endpoint_read(exec_ctx, ep->wrapped_ep, &ep->source_buffer, &ep->on_read); }
static void finish_send_message(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) { call_data *calld = elem->call_data; int did_compress; gpr_slice_buffer tmp; gpr_slice_buffer_init(&tmp); did_compress = grpc_msg_compress(calld->compression_algorithm, &calld->slices, &tmp); if (did_compress) { if (grpc_compression_trace) { char *algo_name; const size_t before_size = calld->slices.length; const size_t after_size = tmp.length; const float savings_ratio = 1.0f - (float)after_size / (float)before_size; GPR_ASSERT(grpc_compression_algorithm_name(calld->compression_algorithm, &algo_name)); gpr_log(GPR_DEBUG, "Compressed[%s] %" PRIuPTR " bytes vs. %" PRIuPTR " bytes (%.2f%% savings)", algo_name, before_size, after_size, 100 * savings_ratio); } gpr_slice_buffer_swap(&calld->slices, &tmp); calld->send_flags |= GRPC_WRITE_INTERNAL_COMPRESS; } else { if (grpc_compression_trace) { char *algo_name; GPR_ASSERT(grpc_compression_algorithm_name(calld->compression_algorithm, &algo_name)); gpr_log(GPR_DEBUG, "Algorithm '%s' enabled but decided not to compress. Input size: " "%" PRIuPTR, algo_name, calld->slices.length); } } gpr_slice_buffer_destroy(&tmp); grpc_slice_buffer_stream_init(&calld->replacement_stream, &calld->slices, calld->send_flags); calld->send_op.send_message = &calld->replacement_stream.base; calld->post_send = calld->send_op.on_complete; calld->send_op.on_complete = &calld->send_done; grpc_call_next_op(exec_ctx, elem, &calld->send_op); }
static void finish_send_message(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) { call_data *calld = elem->call_data; int did_compress; gpr_slice_buffer tmp; gpr_slice_buffer_init(&tmp); did_compress = grpc_msg_compress(calld->compression_algorithm, &calld->slices, &tmp); if (did_compress) { gpr_slice_buffer_swap(&calld->slices, &tmp); calld->send_flags |= GRPC_WRITE_INTERNAL_COMPRESS; } gpr_slice_buffer_destroy(&tmp); grpc_slice_buffer_stream_init(&calld->replacement_stream, &calld->slices, calld->send_flags); calld->send_op.send_message = &calld->replacement_stream.base; calld->post_send = calld->send_op.on_complete; calld->send_op.on_complete = &calld->send_done; grpc_call_next_op(exec_ctx, elem, &calld->send_op); }
int grpc_chttp2_unlocking_check_writes( grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, grpc_chttp2_transport_writing *transport_writing) { grpc_chttp2_stream_global *stream_global; grpc_chttp2_stream_writing *stream_writing; GPR_TIMER_BEGIN("grpc_chttp2_unlocking_check_writes", 0); /* simple writes are queued to qbuf, and flushed here */ gpr_slice_buffer_swap(&transport_global->qbuf, &transport_writing->outbuf); GPR_ASSERT(transport_global->qbuf.count == 0); grpc_chttp2_hpack_compressor_set_max_table_size( &transport_writing->hpack_compressor, transport_global->settings[GRPC_PEER_SETTINGS] [GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE]); if (transport_global->dirtied_local_settings && !transport_global->sent_local_settings) { gpr_slice_buffer_add( &transport_writing->outbuf, grpc_chttp2_settings_create( transport_global->settings[GRPC_SENT_SETTINGS], transport_global->settings[GRPC_LOCAL_SETTINGS], transport_global->force_send_settings, GRPC_CHTTP2_NUM_SETTINGS)); transport_global->force_send_settings = 0; transport_global->dirtied_local_settings = 0; transport_global->sent_local_settings = 1; } GRPC_CHTTP2_FLOW_MOVE_TRANSPORT("write", transport_writing, outgoing_window, transport_global, outgoing_window); if (transport_writing->outgoing_window > 0) { while (grpc_chttp2_list_pop_stalled_by_transport(transport_global, &stream_global)) { grpc_chttp2_become_writable(exec_ctx, transport_global, stream_global, false, "transport.read_flow_control"); } } /* for each grpc_chttp2_stream that's become writable, frame it's data (according to available window sizes) and add to the output buffer */ while (grpc_chttp2_list_pop_writable_stream( transport_global, transport_writing, &stream_global, &stream_writing)) { bool sent_initial_metadata = stream_writing->sent_initial_metadata; bool become_writable = false; stream_writing->id = stream_global->id; stream_writing->read_closed = stream_global->read_closed; GRPC_CHTTP2_FLOW_MOVE_STREAM("write", transport_writing, stream_writing, outgoing_window, stream_global, outgoing_window); if (!sent_initial_metadata && stream_global->send_initial_metadata) { stream_writing->send_initial_metadata = stream_global->send_initial_metadata; stream_global->send_initial_metadata = NULL; become_writable = true; sent_initial_metadata = true; } if (sent_initial_metadata) { if (stream_global->send_message != NULL) { gpr_slice hdr = gpr_slice_malloc(5); uint8_t *p = GPR_SLICE_START_PTR(hdr); uint32_t len = stream_global->send_message->length; GPR_ASSERT(stream_writing->send_message == NULL); p[0] = (stream_global->send_message->flags & GRPC_WRITE_INTERNAL_COMPRESS) != 0; p[1] = (uint8_t)(len >> 24); p[2] = (uint8_t)(len >> 16); p[3] = (uint8_t)(len >> 8); p[4] = (uint8_t)(len); gpr_slice_buffer_add(&stream_writing->flow_controlled_buffer, hdr); if (stream_global->send_message->length > 0) { stream_writing->send_message = stream_global->send_message; } else { stream_writing->send_message = NULL; } stream_writing->stream_fetched = 0; stream_global->send_message = NULL; } if ((stream_writing->send_message != NULL || stream_writing->flow_controlled_buffer.length > 0) && stream_writing->outgoing_window > 0) { if (transport_writing->outgoing_window > 0) { become_writable = true; } else { grpc_chttp2_list_add_stalled_by_transport(transport_writing, stream_writing); } } if (stream_global->send_trailing_metadata) { stream_writing->send_trailing_metadata = stream_global->send_trailing_metadata; stream_global->send_trailing_metadata = NULL; become_writable = true; } } if (!stream_global->read_closed && stream_global->unannounced_incoming_window_for_writing > 1024) { GRPC_CHTTP2_FLOW_MOVE_STREAM("write", transport_global, stream_writing, announce_window, stream_global, unannounced_incoming_window_for_writing); become_writable = true; } if (become_writable) { grpc_chttp2_list_add_writing_stream(transport_writing, stream_writing); } else { GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2_writing"); } }
int grpc_chttp2_unlocking_check_writes( grpc_chttp2_transport_global *transport_global, grpc_chttp2_transport_writing *transport_writing) { grpc_chttp2_stream_global *stream_global; grpc_chttp2_stream_writing *stream_writing; grpc_chttp2_stream_global *first_reinserted_stream = NULL; gpr_uint32 window_delta; /* simple writes are queued to qbuf, and flushed here */ gpr_slice_buffer_swap(&transport_global->qbuf, &transport_writing->outbuf); GPR_ASSERT(transport_global->qbuf.count == 0); if (transport_global->dirtied_local_settings && !transport_global->sent_local_settings) { gpr_slice_buffer_add( &transport_writing->outbuf, grpc_chttp2_settings_create( transport_global->settings[GRPC_SENT_SETTINGS], transport_global->settings[GRPC_LOCAL_SETTINGS], transport_global->force_send_settings, GRPC_CHTTP2_NUM_SETTINGS)); transport_global->force_send_settings = 0; transport_global->dirtied_local_settings = 0; transport_global->sent_local_settings = 1; } /* for each grpc_chttp2_stream that's become writable, frame it's data (according to available window sizes) and add to the output buffer */ while (grpc_chttp2_list_pop_writable_stream( transport_global, transport_writing, &stream_global, &stream_writing)) { if (stream_global == first_reinserted_stream) { /* prevent infinite loop */ grpc_chttp2_list_add_first_writable_stream(transport_global, stream_global); break; } stream_writing->id = stream_global->id; stream_writing->send_closed = GRPC_DONT_SEND_CLOSED; if (stream_global->outgoing_sopb) { window_delta = grpc_chttp2_preencode(stream_global->outgoing_sopb->ops, &stream_global->outgoing_sopb->nops, GPR_MIN(transport_global->outgoing_window, stream_global->outgoing_window), &stream_writing->sopb); GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT( "write", transport_global, outgoing_window, -(gpr_int64)window_delta); GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("write", transport_global, stream_global, outgoing_window, -(gpr_int64)window_delta); transport_global->outgoing_window -= window_delta; stream_global->outgoing_window -= window_delta; if (stream_global->write_state == GRPC_WRITE_STATE_QUEUED_CLOSE && stream_global->outgoing_sopb->nops == 0) { if (!transport_global->is_client && !stream_global->read_closed) { stream_writing->send_closed = GRPC_SEND_CLOSED_WITH_RST_STREAM; } else { stream_writing->send_closed = GRPC_SEND_CLOSED; } } if (stream_global->outgoing_window > 0 && stream_global->outgoing_sopb->nops != 0) { grpc_chttp2_list_add_writable_stream(transport_global, stream_global); if (first_reinserted_stream == NULL && transport_global->outgoing_window == 0) { first_reinserted_stream = stream_global; } } } if (!stream_global->read_closed && stream_global->unannounced_incoming_window > 0) { stream_writing->announce_window = stream_global->unannounced_incoming_window; GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("write", transport_global, stream_global, incoming_window, stream_global->unannounced_incoming_window); GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("write", transport_global, stream_global, unannounced_incoming_window, -(gpr_int64)stream_global->unannounced_incoming_window); stream_global->incoming_window += stream_global->unannounced_incoming_window; stream_global->unannounced_incoming_window = 0; grpc_chttp2_list_add_incoming_window_updated(transport_global, stream_global); stream_global->writing_now |= GRPC_CHTTP2_WRITING_WINDOW; } if (stream_writing->sopb.nops > 0 || stream_writing->send_closed != GRPC_DONT_SEND_CLOSED) { stream_global->writing_now |= GRPC_CHTTP2_WRITING_DATA; } if (stream_global->writing_now != 0) { grpc_chttp2_list_add_writing_stream(transport_writing, stream_writing); } } /* if the grpc_chttp2_transport is ready to send a window update, do so here also; 3/4 is a magic number that will likely get tuned soon */ if (transport_global->incoming_window < transport_global->connection_window_target * 3 / 4) { window_delta = transport_global->connection_window_target - transport_global->incoming_window; gpr_slice_buffer_add(&transport_writing->outbuf, grpc_chttp2_window_update_create(0, window_delta)); GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT("write", transport_global, incoming_window, window_delta); transport_global->incoming_window += window_delta; } return transport_writing->outbuf.count > 0 || grpc_chttp2_list_have_writing_streams(transport_writing); }