static void maybe_start_some_streams( grpc_chttp2_transport_global *transport_global) { grpc_chttp2_stream_global *stream_global; /* start streams where we have free grpc_chttp2_stream ids and free * concurrency */ while (transport_global->next_stream_id <= MAX_CLIENT_STREAM_ID && transport_global->concurrent_stream_count < transport_global ->settings[GRPC_PEER_SETTINGS] [GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS] && grpc_chttp2_list_pop_waiting_for_concurrency(transport_global, &stream_global)) { GRPC_CHTTP2_IF_TRACING(gpr_log( GPR_DEBUG, "HTTP:%s: Allocating new grpc_chttp2_stream %p to id %d", transport_global->is_client ? "CLI" : "SVR", stream_global, transport_global->next_stream_id)); GPR_ASSERT(stream_global->id == 0); stream_global->id = transport_global->next_stream_id; transport_global->next_stream_id += 2; if (transport_global->next_stream_id >= MAX_CLIENT_STREAM_ID) { connectivity_state_set(transport_global, GRPC_CHANNEL_TRANSIENT_FAILURE, "no_more_stream_ids"); } stream_global->outgoing_window = transport_global->settings[GRPC_PEER_SETTINGS] [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; stream_global->incoming_window = transport_global->settings[GRPC_SENT_SETTINGS] [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; stream_global->max_recv_bytes = GPR_MAX(stream_global->incoming_window, stream_global->max_recv_bytes); grpc_chttp2_stream_map_add( &TRANSPORT_FROM_GLOBAL(transport_global)->new_stream_map, stream_global->id, STREAM_FROM_GLOBAL(stream_global)); stream_global->in_stream_map = 1; transport_global->concurrent_stream_count++; grpc_chttp2_list_add_incoming_window_updated(transport_global, stream_global); grpc_chttp2_list_add_writable_stream(transport_global, stream_global); } /* cancel out streams that will never be started */ while (transport_global->next_stream_id >= MAX_CLIENT_STREAM_ID && grpc_chttp2_list_pop_waiting_for_concurrency(transport_global, &stream_global)) { cancel_from_api(transport_global, stream_global, GRPC_STATUS_UNAVAILABLE); } }
/* add a bunch of keys, delete the even ones immediately, and make sure the map is consistent */ static void test_delete_evens_incremental(uint32_t n) { grpc_chttp2_stream_map map; uint32_t i; LOG_TEST("test_delete_evens_incremental"); gpr_log(GPR_INFO, "n = %d", n); grpc_chttp2_stream_map_init(&map, 8); for (i = 1; i <= n; i++) { grpc_chttp2_stream_map_add(&map, i, (void *)(uintptr_t)i); if ((i & 1) == 0) { grpc_chttp2_stream_map_delete(&map, i); } } check_delete_evens(&map, n); grpc_chttp2_stream_map_destroy(&map); }
/* test it's safe to delete twice */ static void test_double_deletion(void) { grpc_chttp2_stream_map map; LOG_TEST("test_double_deletion"); grpc_chttp2_stream_map_init(&map, 8); GPR_ASSERT(0 == grpc_chttp2_stream_map_size(&map)); grpc_chttp2_stream_map_add(&map, 1, (void *)1); GPR_ASSERT((void *)1 == grpc_chttp2_stream_map_find(&map, 1)); GPR_ASSERT(1 == grpc_chttp2_stream_map_size(&map)); GPR_ASSERT((void *)1 == grpc_chttp2_stream_map_delete(&map, 1)); GPR_ASSERT(0 == grpc_chttp2_stream_map_size(&map)); GPR_ASSERT(NULL == grpc_chttp2_stream_map_find(&map, 1)); GPR_ASSERT(NULL == grpc_chttp2_stream_map_delete(&map, 1)); GPR_ASSERT(NULL == grpc_chttp2_stream_map_find(&map, 1)); GPR_ASSERT(NULL == grpc_chttp2_stream_map_delete(&map, 1)); GPR_ASSERT(NULL == grpc_chttp2_stream_map_find(&map, 1)); GPR_ASSERT(NULL == grpc_chttp2_stream_map_delete(&map, 1)); GPR_ASSERT(NULL == grpc_chttp2_stream_map_find(&map, 1)); grpc_chttp2_stream_map_destroy(&map); }
/* add a bunch of keys, delete old ones after some time, ensure the backing array does not grow */ static void test_periodic_compaction(uint32_t n) { grpc_chttp2_stream_map map; uint32_t i; uint32_t del; LOG_TEST("test_periodic_compaction"); gpr_log(GPR_INFO, "n = %d", n); grpc_chttp2_stream_map_init(&map, 16); GPR_ASSERT(map.capacity == 16); for (i = 1; i <= n; i++) { grpc_chttp2_stream_map_add(&map, i, (void *)(uintptr_t)i); if (i > 8) { del = i - 8; GPR_ASSERT((void *)(uintptr_t)del == grpc_chttp2_stream_map_delete(&map, del)); } } GPR_ASSERT(map.capacity == 16); grpc_chttp2_stream_map_destroy(&map); }
static int init_stream(grpc_transport *gt, grpc_stream *gs, const void *server_data, grpc_transport_stream_op *initial_op) { grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt; grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs; memset(s, 0, sizeof(*s)); grpc_chttp2_incoming_metadata_buffer_init(&s->parsing.incoming_metadata); grpc_chttp2_incoming_metadata_buffer_init(&s->global.incoming_metadata); grpc_sopb_init(&s->writing.sopb); grpc_sopb_init(&s->global.incoming_sopb); grpc_chttp2_data_parser_init(&s->parsing.data_parser); REF_TRANSPORT(t, "stream"); lock(t); grpc_chttp2_register_stream(t, s); if (server_data) { GPR_ASSERT(t->parsing_active); s->global.id = (gpr_uint32)(gpr_uintptr)server_data; s->global.outgoing_window = t->global.settings[GRPC_PEER_SETTINGS] [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; s->global.max_recv_bytes = s->parsing.incoming_window = s->global.incoming_window = t->global.settings[GRPC_SENT_SETTINGS] [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; *t->accepting_stream = s; grpc_chttp2_stream_map_add(&t->parsing_stream_map, s->global.id, s); s->global.in_stream_map = 1; } if (initial_op) perform_stream_op_locked(&t->global, &s->global, initial_op); unlock(t); return 0; }
/* test add & lookup */ static void test_basic_add_find(uint32_t n) { grpc_chttp2_stream_map map; uint32_t i; size_t got; LOG_TEST("test_basic_add_find"); gpr_log(GPR_INFO, "n = %d", n); grpc_chttp2_stream_map_init(&map, 8); GPR_ASSERT(0 == grpc_chttp2_stream_map_size(&map)); for (i = 1; i <= n; i++) { grpc_chttp2_stream_map_add(&map, i, (void *)(uintptr_t)i); } GPR_ASSERT(n == grpc_chttp2_stream_map_size(&map)); GPR_ASSERT(NULL == grpc_chttp2_stream_map_find(&map, 0)); GPR_ASSERT(NULL == grpc_chttp2_stream_map_find(&map, n + 1)); for (i = 1; i <= n; i++) { got = (uintptr_t)grpc_chttp2_stream_map_find(&map, i); GPR_ASSERT(i == got); } grpc_chttp2_stream_map_destroy(&map); }