grpc 1.9.0.pre2 → 1.9.0.pre3
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of grpc might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/Makefile +27 -3
- data/src/core/ext/filters/client_channel/client_channel.cc +4 -4
- data/src/core/ext/filters/client_channel/lb_policy.h +3 -4
- data/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc +2 -2
- data/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc +56 -19
- data/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc +32 -31
- data/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc +4 -1
- data/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h +1 -2
- data/src/core/ext/filters/client_channel/subchannel.cc +150 -146
- data/src/core/ext/filters/client_channel/subchannel.h +43 -34
- data/src/core/lib/surface/call.cc +1 -0
- data/src/core/lib/surface/version.cc +1 -1
- data/src/ruby/lib/grpc/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 42b494831008d6915361053c5d39fa06f4c274daa76376ed1d73994ba56a8ed1
|
4
|
+
data.tar.gz: 59c61af48ea465e644657e57ff7f8f01ed18ab597f84542add663891e88d22a5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3787efa86a57047f1cc1c2c39539c580ee191157eb3ab5d3024abfeb8a7af0ac25100d402f09ef41702b885df95bd684389f4ea14ce59abdc22bce9e48b32524
|
7
|
+
data.tar.gz: 135ff4dbbef3ffd794266da6852acac137f1e2e4de06b438dfa7ff547cbf8c5802da3d262b1a9ee496bbc95e3ec738867bf2cae2fe978c67dac2ab19c1810b9b
|
data/Makefile
CHANGED
@@ -418,9 +418,9 @@ E = @echo
|
|
418
418
|
Q = @
|
419
419
|
endif
|
420
420
|
|
421
|
-
CORE_VERSION = 5.0.0-
|
422
|
-
CPP_VERSION = 1.9.0-
|
423
|
-
CSHARP_VERSION = 1.9.0-
|
421
|
+
CORE_VERSION = 5.0.0-pre3
|
422
|
+
CPP_VERSION = 1.9.0-pre3
|
423
|
+
CSHARP_VERSION = 1.9.0-pre3
|
424
424
|
|
425
425
|
CPPFLAGS_NO_ARCH += $(addprefix -I, $(INCLUDES)) $(addprefix -D, $(DEFINES))
|
426
426
|
CPPFLAGS += $(CPPFLAGS_NO_ARCH) $(ARCH_FLAGS)
|
@@ -1233,6 +1233,7 @@ boringssl_tab_test: $(BINDIR)/$(CONFIG)/boringssl_tab_test
|
|
1233
1233
|
boringssl_v3name_test: $(BINDIR)/$(CONFIG)/boringssl_v3name_test
|
1234
1234
|
badreq_bad_client_test: $(BINDIR)/$(CONFIG)/badreq_bad_client_test
|
1235
1235
|
connection_prefix_bad_client_test: $(BINDIR)/$(CONFIG)/connection_prefix_bad_client_test
|
1236
|
+
duplicate_header_bad_client_test: $(BINDIR)/$(CONFIG)/duplicate_header_bad_client_test
|
1236
1237
|
head_of_line_blocking_bad_client_test: $(BINDIR)/$(CONFIG)/head_of_line_blocking_bad_client_test
|
1237
1238
|
headers_bad_client_test: $(BINDIR)/$(CONFIG)/headers_bad_client_test
|
1238
1239
|
initial_settings_frame_bad_client_test: $(BINDIR)/$(CONFIG)/initial_settings_frame_bad_client_test
|
@@ -1485,6 +1486,7 @@ buildtests_c: privatelibs_c \
|
|
1485
1486
|
$(BINDIR)/$(CONFIG)/public_headers_must_be_c89 \
|
1486
1487
|
$(BINDIR)/$(CONFIG)/badreq_bad_client_test \
|
1487
1488
|
$(BINDIR)/$(CONFIG)/connection_prefix_bad_client_test \
|
1489
|
+
$(BINDIR)/$(CONFIG)/duplicate_header_bad_client_test \
|
1488
1490
|
$(BINDIR)/$(CONFIG)/head_of_line_blocking_bad_client_test \
|
1489
1491
|
$(BINDIR)/$(CONFIG)/headers_bad_client_test \
|
1490
1492
|
$(BINDIR)/$(CONFIG)/initial_settings_frame_bad_client_test \
|
@@ -2023,6 +2025,8 @@ test_c: buildtests_c
|
|
2023
2025
|
$(Q) $(BINDIR)/$(CONFIG)/badreq_bad_client_test || ( echo test badreq_bad_client_test failed ; exit 1 )
|
2024
2026
|
$(E) "[RUN] Testing connection_prefix_bad_client_test"
|
2025
2027
|
$(Q) $(BINDIR)/$(CONFIG)/connection_prefix_bad_client_test || ( echo test connection_prefix_bad_client_test failed ; exit 1 )
|
2028
|
+
$(E) "[RUN] Testing duplicate_header_bad_client_test"
|
2029
|
+
$(Q) $(BINDIR)/$(CONFIG)/duplicate_header_bad_client_test || ( echo test duplicate_header_bad_client_test failed ; exit 1 )
|
2026
2030
|
$(E) "[RUN] Testing head_of_line_blocking_bad_client_test"
|
2027
2031
|
$(Q) $(BINDIR)/$(CONFIG)/head_of_line_blocking_bad_client_test || ( echo test head_of_line_blocking_bad_client_test failed ; exit 1 )
|
2028
2032
|
$(E) "[RUN] Testing headers_bad_client_test"
|
@@ -18726,6 +18730,26 @@ ifneq ($(NO_DEPS),true)
|
|
18726
18730
|
endif
|
18727
18731
|
|
18728
18732
|
|
18733
|
+
DUPLICATE_HEADER_BAD_CLIENT_TEST_SRC = \
|
18734
|
+
test/core/bad_client/tests/duplicate_header.cc \
|
18735
|
+
|
18736
|
+
DUPLICATE_HEADER_BAD_CLIENT_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(DUPLICATE_HEADER_BAD_CLIENT_TEST_SRC))))
|
18737
|
+
|
18738
|
+
|
18739
|
+
$(BINDIR)/$(CONFIG)/duplicate_header_bad_client_test: $(DUPLICATE_HEADER_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
|
18740
|
+
$(E) "[LD] Linking $@"
|
18741
|
+
$(Q) mkdir -p `dirname $@`
|
18742
|
+
$(Q) $(LD) $(LDFLAGS) $(DUPLICATE_HEADER_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/duplicate_header_bad_client_test
|
18743
|
+
|
18744
|
+
$(OBJDIR)/$(CONFIG)/test/core/bad_client/tests/duplicate_header.o: $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
|
18745
|
+
|
18746
|
+
deps_duplicate_header_bad_client_test: $(DUPLICATE_HEADER_BAD_CLIENT_TEST_OBJS:.o=.dep)
|
18747
|
+
|
18748
|
+
ifneq ($(NO_DEPS),true)
|
18749
|
+
-include $(DUPLICATE_HEADER_BAD_CLIENT_TEST_OBJS:.o=.dep)
|
18750
|
+
endif
|
18751
|
+
|
18752
|
+
|
18729
18753
|
HEAD_OF_LINE_BLOCKING_BAD_CLIENT_TEST_SRC = \
|
18730
18754
|
test/core/bad_client/tests/head_of_line_blocking.cc \
|
18731
18755
|
|
@@ -1003,7 +1003,7 @@ static void create_subchannel_call_locked(grpc_call_element* elem,
|
|
1003
1003
|
grpc_error* error) {
|
1004
1004
|
channel_data* chand = (channel_data*)elem->channel_data;
|
1005
1005
|
call_data* calld = (call_data*)elem->call_data;
|
1006
|
-
const
|
1006
|
+
const grpc_connected_subchannel_call_args call_args = {
|
1007
1007
|
calld->pollent, // pollent
|
1008
1008
|
calld->path, // path
|
1009
1009
|
calld->call_start_time, // start_time
|
@@ -1012,8 +1012,8 @@ static void create_subchannel_call_locked(grpc_call_element* elem,
|
|
1012
1012
|
calld->pick.subchannel_call_context, // context
|
1013
1013
|
calld->call_combiner // call_combiner
|
1014
1014
|
};
|
1015
|
-
grpc_error* new_error =
|
1016
|
-
call_args, &calld->subchannel_call);
|
1015
|
+
grpc_error* new_error = grpc_connected_subchannel_create_call(
|
1016
|
+
calld->pick.connected_subchannel, &call_args, &calld->subchannel_call);
|
1017
1017
|
if (grpc_client_channel_trace.enabled()) {
|
1018
1018
|
gpr_log(GPR_DEBUG, "chand=%p calld=%p: create subchannel_call=%p: error=%s",
|
1019
1019
|
chand, calld, calld->subchannel_call, grpc_error_string(new_error));
|
@@ -1463,7 +1463,7 @@ static void cc_destroy_call_elem(grpc_call_element* elem,
|
|
1463
1463
|
}
|
1464
1464
|
GPR_ASSERT(calld->waiting_for_pick_batches_count == 0);
|
1465
1465
|
if (calld->pick.connected_subchannel != nullptr) {
|
1466
|
-
calld->pick.connected_subchannel
|
1466
|
+
GRPC_CONNECTED_SUBCHANNEL_UNREF(calld->pick.connected_subchannel, "picked");
|
1467
1467
|
}
|
1468
1468
|
for (size_t i = 0; i < GRPC_CONTEXT_COUNT; ++i) {
|
1469
1469
|
if (calld->pick.subchannel_call_context[i].value != nullptr) {
|
@@ -55,9 +55,9 @@ typedef struct grpc_lb_policy_pick_state {
|
|
55
55
|
grpc_linked_mdelem lb_token_mdelem_storage;
|
56
56
|
/// Closure to run when pick is complete, if not completed synchronously.
|
57
57
|
grpc_closure* on_complete;
|
58
|
-
/// Will be set to the selected subchannel, or
|
58
|
+
/// Will be set to the selected subchannel, or NULL on failure or when
|
59
59
|
/// the LB policy decides to drop the call.
|
60
|
-
|
60
|
+
grpc_connected_subchannel* connected_subchannel;
|
61
61
|
/// Will be populated with context to pass to the subchannel call, if needed.
|
62
62
|
grpc_call_context_element subchannel_call_context[GRPC_CONTEXT_COUNT];
|
63
63
|
/// Upon success, \a *user_data will be set to whatever opaque information
|
@@ -153,8 +153,7 @@ void grpc_lb_policy_shutdown_locked(grpc_lb_policy* policy,
|
|
153
153
|
int grpc_lb_policy_pick_locked(grpc_lb_policy* policy,
|
154
154
|
grpc_lb_policy_pick_state* pick);
|
155
155
|
|
156
|
-
/** Perform a connected subchannel ping (see \a
|
157
|
-
grpc_core::ConnectedSubchannel::Ping)
|
156
|
+
/** Perform a connected subchannel ping (see \a grpc_connected_subchannel_ping)
|
158
157
|
against one of the connected subchannels managed by \a policy. */
|
159
158
|
void grpc_lb_policy_ping_one_locked(grpc_lb_policy* policy,
|
160
159
|
grpc_closure* on_initiate,
|
@@ -939,7 +939,7 @@ static void glb_shutdown_locked(grpc_lb_policy* pol,
|
|
939
939
|
}
|
940
940
|
gpr_free(pp);
|
941
941
|
} else {
|
942
|
-
pp->pick->connected_subchannel
|
942
|
+
pp->pick->connected_subchannel = nullptr;
|
943
943
|
GRPC_CLOSURE_SCHED(&pp->on_complete, GRPC_ERROR_REF(error));
|
944
944
|
}
|
945
945
|
pp = next;
|
@@ -976,7 +976,7 @@ static void glb_cancel_pick_locked(grpc_lb_policy* pol,
|
|
976
976
|
while (pp != nullptr) {
|
977
977
|
pending_pick* next = pp->next;
|
978
978
|
if (pp->pick == pick) {
|
979
|
-
pick->connected_subchannel
|
979
|
+
pick->connected_subchannel = nullptr;
|
980
980
|
GRPC_CLOSURE_SCHED(&pp->on_complete,
|
981
981
|
GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
|
982
982
|
"Pick Cancelled", &error, 1));
|
@@ -81,7 +81,7 @@ static void pf_shutdown_locked(grpc_lb_policy* pol,
|
|
81
81
|
GRPC_CLOSURE_SCHED(pick->on_complete, GRPC_ERROR_NONE);
|
82
82
|
}
|
83
83
|
} else {
|
84
|
-
pick->connected_subchannel
|
84
|
+
pick->connected_subchannel = nullptr;
|
85
85
|
GRPC_CLOSURE_SCHED(pick->on_complete, GRPC_ERROR_REF(error));
|
86
86
|
}
|
87
87
|
}
|
@@ -111,7 +111,7 @@ static void pf_cancel_pick_locked(grpc_lb_policy* pol,
|
|
111
111
|
while (pp != nullptr) {
|
112
112
|
grpc_lb_policy_pick_state* next = pp->next;
|
113
113
|
if (pp == pick) {
|
114
|
-
pick->connected_subchannel
|
114
|
+
pick->connected_subchannel = nullptr;
|
115
115
|
GRPC_CLOSURE_SCHED(pick->on_complete,
|
116
116
|
GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
|
117
117
|
"Pick Cancelled", &error, 1));
|
@@ -176,7 +176,8 @@ static int pf_pick_locked(grpc_lb_policy* pol,
|
|
176
176
|
pick_first_lb_policy* p = (pick_first_lb_policy*)pol;
|
177
177
|
// If we have a selected subchannel already, return synchronously.
|
178
178
|
if (p->selected != nullptr) {
|
179
|
-
pick->connected_subchannel =
|
179
|
+
pick->connected_subchannel = GRPC_CONNECTED_SUBCHANNEL_REF(
|
180
|
+
p->selected->connected_subchannel, "picked");
|
180
181
|
return 1;
|
181
182
|
}
|
182
183
|
// No subchannel selected yet, so handle asynchronously.
|
@@ -216,7 +217,8 @@ static void pf_ping_one_locked(grpc_lb_policy* pol, grpc_closure* on_initiate,
|
|
216
217
|
grpc_closure* on_ack) {
|
217
218
|
pick_first_lb_policy* p = (pick_first_lb_policy*)pol;
|
218
219
|
if (p->selected) {
|
219
|
-
p->selected->connected_subchannel
|
220
|
+
grpc_connected_subchannel_ping(p->selected->connected_subchannel,
|
221
|
+
on_initiate, on_ack);
|
220
222
|
} else {
|
221
223
|
GRPC_CLOSURE_SCHED(on_initiate,
|
222
224
|
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Not connected"));
|
@@ -295,7 +297,8 @@ static void pf_update_locked(grpc_lb_policy* policy,
|
|
295
297
|
subchannel_list->num_subchannels);
|
296
298
|
}
|
297
299
|
if (p->selected->connected_subchannel != nullptr) {
|
298
|
-
sd->connected_subchannel =
|
300
|
+
sd->connected_subchannel = GRPC_CONNECTED_SUBCHANNEL_REF(
|
301
|
+
p->selected->connected_subchannel, "pf_update_includes_selected");
|
299
302
|
}
|
300
303
|
p->selected = sd;
|
301
304
|
if (p->subchannel_list != nullptr) {
|
@@ -407,8 +410,8 @@ static void pf_connectivity_changed_locked(void* arg, grpc_error* error) {
|
|
407
410
|
// re-resolution is introduced. But we need to investigate whether we
|
408
411
|
// really want to take any action instead of waiting for the selected
|
409
412
|
// subchannel reconnecting.
|
410
|
-
|
411
|
-
|
413
|
+
if (sd->curr_connectivity_state == GRPC_CHANNEL_SHUTDOWN ||
|
414
|
+
sd->curr_connectivity_state == GRPC_CHANNEL_TRANSIENT_FAILURE) {
|
412
415
|
// If the selected channel goes bad, request a re-resolution.
|
413
416
|
grpc_connectivity_state_set(&p->state_tracker, GRPC_CHANNEL_IDLE,
|
414
417
|
GRPC_ERROR_NONE,
|
@@ -416,19 +419,20 @@ static void pf_connectivity_changed_locked(void* arg, grpc_error* error) {
|
|
416
419
|
p->started_picking = false;
|
417
420
|
grpc_lb_policy_try_reresolve(&p->base, &grpc_lb_pick_first_trace,
|
418
421
|
GRPC_ERROR_NONE);
|
419
|
-
// in transient failure. Rely on re-resolution to recover.
|
420
|
-
p->selected = nullptr;
|
421
|
-
grpc_lb_subchannel_data_stop_connectivity_watch(sd);
|
422
|
-
grpc_lb_subchannel_list_unref_for_connectivity_watch(
|
423
|
-
sd->subchannel_list, "pf_selected_shutdown");
|
424
|
-
grpc_lb_subchannel_data_unref_subchannel(
|
425
|
-
sd, "pf_selected_shutdown"); // Unrefs connected subchannel
|
426
422
|
} else {
|
427
423
|
grpc_connectivity_state_set(&p->state_tracker,
|
428
424
|
sd->curr_connectivity_state,
|
429
425
|
GRPC_ERROR_REF(error), "selected_changed");
|
426
|
+
}
|
427
|
+
if (sd->curr_connectivity_state != GRPC_CHANNEL_SHUTDOWN) {
|
430
428
|
// Renew notification.
|
431
429
|
grpc_lb_subchannel_data_start_connectivity_watch(sd);
|
430
|
+
} else {
|
431
|
+
p->selected = nullptr;
|
432
|
+
grpc_lb_subchannel_data_stop_connectivity_watch(sd);
|
433
|
+
grpc_lb_subchannel_list_unref_for_connectivity_watch(
|
434
|
+
sd->subchannel_list, "pf_selected_shutdown");
|
435
|
+
grpc_lb_subchannel_data_unref_subchannel(sd, "pf_selected_shutdown");
|
432
436
|
}
|
433
437
|
}
|
434
438
|
return;
|
@@ -446,8 +450,6 @@ static void pf_connectivity_changed_locked(void* arg, grpc_error* error) {
|
|
446
450
|
case GRPC_CHANNEL_READY: {
|
447
451
|
// Case 2. Promote p->latest_pending_subchannel_list to
|
448
452
|
// p->subchannel_list.
|
449
|
-
sd->connected_subchannel =
|
450
|
-
grpc_subchannel_get_connected_subchannel(sd->subchannel);
|
451
453
|
if (sd->subchannel_list == p->latest_pending_subchannel_list) {
|
452
454
|
GPR_ASSERT(p->subchannel_list != nullptr);
|
453
455
|
grpc_lb_subchannel_list_shutdown_and_unref(p->subchannel_list,
|
@@ -458,6 +460,9 @@ static void pf_connectivity_changed_locked(void* arg, grpc_error* error) {
|
|
458
460
|
// Cases 1 and 2.
|
459
461
|
grpc_connectivity_state_set(&p->state_tracker, GRPC_CHANNEL_READY,
|
460
462
|
GRPC_ERROR_NONE, "connecting_ready");
|
463
|
+
sd->connected_subchannel = GRPC_CONNECTED_SUBCHANNEL_REF(
|
464
|
+
grpc_subchannel_get_connected_subchannel(sd->subchannel),
|
465
|
+
"connected");
|
461
466
|
p->selected = sd;
|
462
467
|
if (grpc_lb_pick_first_trace.enabled()) {
|
463
468
|
gpr_log(GPR_INFO, "Pick First %p selected subchannel %p", (void*)p,
|
@@ -469,7 +474,8 @@ static void pf_connectivity_changed_locked(void* arg, grpc_error* error) {
|
|
469
474
|
grpc_lb_policy_pick_state* pick;
|
470
475
|
while ((pick = p->pending_picks)) {
|
471
476
|
p->pending_picks = pick->next;
|
472
|
-
pick->connected_subchannel =
|
477
|
+
pick->connected_subchannel = GRPC_CONNECTED_SUBCHANNEL_REF(
|
478
|
+
p->selected->connected_subchannel, "picked");
|
473
479
|
if (grpc_lb_pick_first_trace.enabled()) {
|
474
480
|
gpr_log(GPR_INFO,
|
475
481
|
"Servicing pending pick with selected subchannel %p",
|
@@ -514,8 +520,39 @@ static void pf_connectivity_changed_locked(void* arg, grpc_error* error) {
|
|
514
520
|
grpc_lb_subchannel_data_start_connectivity_watch(sd);
|
515
521
|
break;
|
516
522
|
}
|
517
|
-
case GRPC_CHANNEL_SHUTDOWN:
|
518
|
-
|
523
|
+
case GRPC_CHANNEL_SHUTDOWN: {
|
524
|
+
grpc_lb_subchannel_data_stop_connectivity_watch(sd);
|
525
|
+
grpc_lb_subchannel_data_unref_subchannel(sd, "pf_candidate_shutdown");
|
526
|
+
// Advance to next subchannel and check its state.
|
527
|
+
grpc_lb_subchannel_data* original_sd = sd;
|
528
|
+
do {
|
529
|
+
sd->subchannel_list->checking_subchannel =
|
530
|
+
(sd->subchannel_list->checking_subchannel + 1) %
|
531
|
+
sd->subchannel_list->num_subchannels;
|
532
|
+
sd = &sd->subchannel_list
|
533
|
+
->subchannels[sd->subchannel_list->checking_subchannel];
|
534
|
+
} while (sd->subchannel == nullptr && sd != original_sd);
|
535
|
+
if (sd == original_sd) {
|
536
|
+
grpc_lb_subchannel_list_unref_for_connectivity_watch(
|
537
|
+
sd->subchannel_list, "pf_exhausted_subchannels");
|
538
|
+
if (sd->subchannel_list == p->subchannel_list) {
|
539
|
+
grpc_connectivity_state_set(&p->state_tracker, GRPC_CHANNEL_IDLE,
|
540
|
+
GRPC_ERROR_NONE,
|
541
|
+
"exhausted_subchannels+reresolve");
|
542
|
+
p->started_picking = false;
|
543
|
+
grpc_lb_policy_try_reresolve(&p->base, &grpc_lb_pick_first_trace,
|
544
|
+
GRPC_ERROR_NONE);
|
545
|
+
}
|
546
|
+
} else {
|
547
|
+
if (sd->subchannel_list == p->subchannel_list) {
|
548
|
+
grpc_connectivity_state_set(
|
549
|
+
&p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE,
|
550
|
+
GRPC_ERROR_REF(error), "subchannel_failed");
|
551
|
+
}
|
552
|
+
// Reuses the connectivity refs from the previous watch.
|
553
|
+
grpc_lb_subchannel_data_start_connectivity_watch(sd);
|
554
|
+
}
|
555
|
+
}
|
519
556
|
}
|
520
557
|
}
|
521
558
|
|
@@ -128,7 +128,7 @@ static void update_last_ready_subchannel_index_locked(round_robin_lb_policy* p,
|
|
128
128
|
(void*)p, (unsigned long)last_ready_index,
|
129
129
|
(void*)p->subchannel_list->subchannels[last_ready_index].subchannel,
|
130
130
|
(void*)p->subchannel_list->subchannels[last_ready_index]
|
131
|
-
.connected_subchannel
|
131
|
+
.connected_subchannel);
|
132
132
|
}
|
133
133
|
}
|
134
134
|
|
@@ -163,7 +163,7 @@ static void rr_shutdown_locked(grpc_lb_policy* pol,
|
|
163
163
|
GRPC_CLOSURE_SCHED(pick->on_complete, GRPC_ERROR_NONE);
|
164
164
|
}
|
165
165
|
} else {
|
166
|
-
pick->connected_subchannel
|
166
|
+
pick->connected_subchannel = nullptr;
|
167
167
|
GRPC_CLOSURE_SCHED(pick->on_complete, GRPC_ERROR_REF(error));
|
168
168
|
}
|
169
169
|
}
|
@@ -193,7 +193,7 @@ static void rr_cancel_pick_locked(grpc_lb_policy* pol,
|
|
193
193
|
while (pp != nullptr) {
|
194
194
|
grpc_lb_policy_pick_state* next = pp->next;
|
195
195
|
if (pp == pick) {
|
196
|
-
pick->connected_subchannel
|
196
|
+
pick->connected_subchannel = nullptr;
|
197
197
|
GRPC_CLOSURE_SCHED(pick->on_complete,
|
198
198
|
GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
|
199
199
|
"Pick cancelled", &error, 1));
|
@@ -217,7 +217,7 @@ static void rr_cancel_picks_locked(grpc_lb_policy* pol,
|
|
217
217
|
grpc_lb_policy_pick_state* next = pick->next;
|
218
218
|
if ((pick->initial_metadata_flags & initial_metadata_flags_mask) ==
|
219
219
|
initial_metadata_flags_eq) {
|
220
|
-
pick->connected_subchannel
|
220
|
+
pick->connected_subchannel = nullptr;
|
221
221
|
GRPC_CLOSURE_SCHED(pick->on_complete,
|
222
222
|
GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
|
223
223
|
"Pick cancelled", &error, 1));
|
@@ -263,7 +263,8 @@ static int rr_pick_locked(grpc_lb_policy* pol,
|
|
263
263
|
/* readily available, report right away */
|
264
264
|
grpc_lb_subchannel_data* sd =
|
265
265
|
&p->subchannel_list->subchannels[next_ready_index];
|
266
|
-
pick->connected_subchannel =
|
266
|
+
pick->connected_subchannel =
|
267
|
+
GRPC_CONNECTED_SUBCHANNEL_REF(sd->connected_subchannel, "rr_picked");
|
267
268
|
if (pick->user_data != nullptr) {
|
268
269
|
*pick->user_data = sd->user_data;
|
269
270
|
}
|
@@ -272,8 +273,8 @@ static int rr_pick_locked(grpc_lb_policy* pol,
|
|
272
273
|
GPR_DEBUG,
|
273
274
|
"[RR %p] Picked target <-- Subchannel %p (connected %p) (sl %p, "
|
274
275
|
"index %" PRIuPTR ")",
|
275
|
-
p, sd->subchannel, pick->connected_subchannel
|
276
|
-
|
276
|
+
p, sd->subchannel, pick->connected_subchannel, sd->subchannel_list,
|
277
|
+
next_ready_index);
|
277
278
|
}
|
278
279
|
/* only advance the last picked pointer if the selection was used */
|
279
280
|
update_last_ready_subchannel_index_locked(p, next_ready_index);
|
@@ -291,14 +292,15 @@ static int rr_pick_locked(grpc_lb_policy* pol,
|
|
291
292
|
|
292
293
|
static void update_state_counters_locked(grpc_lb_subchannel_data* sd) {
|
293
294
|
grpc_lb_subchannel_list* subchannel_list = sd->subchannel_list;
|
294
|
-
GPR_ASSERT(sd->prev_connectivity_state != GRPC_CHANNEL_SHUTDOWN);
|
295
|
-
GPR_ASSERT(sd->curr_connectivity_state != GRPC_CHANNEL_SHUTDOWN);
|
296
295
|
if (sd->prev_connectivity_state == GRPC_CHANNEL_READY) {
|
297
296
|
GPR_ASSERT(subchannel_list->num_ready > 0);
|
298
297
|
--subchannel_list->num_ready;
|
299
298
|
} else if (sd->prev_connectivity_state == GRPC_CHANNEL_TRANSIENT_FAILURE) {
|
300
299
|
GPR_ASSERT(subchannel_list->num_transient_failures > 0);
|
301
300
|
--subchannel_list->num_transient_failures;
|
301
|
+
} else if (sd->prev_connectivity_state == GRPC_CHANNEL_SHUTDOWN) {
|
302
|
+
GPR_ASSERT(subchannel_list->num_shutdown > 0);
|
303
|
+
--subchannel_list->num_shutdown;
|
302
304
|
} else if (sd->prev_connectivity_state == GRPC_CHANNEL_IDLE) {
|
303
305
|
GPR_ASSERT(subchannel_list->num_idle > 0);
|
304
306
|
--subchannel_list->num_idle;
|
@@ -308,6 +310,8 @@ static void update_state_counters_locked(grpc_lb_subchannel_data* sd) {
|
|
308
310
|
++subchannel_list->num_ready;
|
309
311
|
} else if (sd->curr_connectivity_state == GRPC_CHANNEL_TRANSIENT_FAILURE) {
|
310
312
|
++subchannel_list->num_transient_failures;
|
313
|
+
} else if (sd->curr_connectivity_state == GRPC_CHANNEL_SHUTDOWN) {
|
314
|
+
++subchannel_list->num_shutdown;
|
311
315
|
} else if (sd->curr_connectivity_state == GRPC_CHANNEL_IDLE) {
|
312
316
|
++subchannel_list->num_idle;
|
313
317
|
}
|
@@ -407,7 +411,6 @@ static void rr_connectivity_changed_locked(void* arg, grpc_error* error) {
|
|
407
411
|
// either the current or latest pending subchannel lists.
|
408
412
|
GPR_ASSERT(sd->subchannel_list == p->subchannel_list ||
|
409
413
|
sd->subchannel_list == p->latest_pending_subchannel_list);
|
410
|
-
GPR_ASSERT(sd->pending_connectivity_state_unsafe != GRPC_CHANNEL_SHUTDOWN);
|
411
414
|
// Now that we're inside the combiner, copy the pending connectivity
|
412
415
|
// state (which was set by the connectivity state watcher) to
|
413
416
|
// curr_connectivity_state, which is what we use inside of the combiner.
|
@@ -415,17 +418,18 @@ static void rr_connectivity_changed_locked(void* arg, grpc_error* error) {
|
|
415
418
|
// Update state counters and new overall state.
|
416
419
|
update_state_counters_locked(sd);
|
417
420
|
update_lb_connectivity_status_locked(sd, GRPC_ERROR_REF(error));
|
418
|
-
// If the sd's new state is
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
421
|
+
// If the sd's new state is SHUTDOWN, unref the subchannel.
|
422
|
+
if (sd->curr_connectivity_state == GRPC_CHANNEL_SHUTDOWN) {
|
423
|
+
grpc_lb_subchannel_data_stop_connectivity_watch(sd);
|
424
|
+
grpc_lb_subchannel_data_unref_subchannel(sd, "rr_connectivity_shutdown");
|
425
|
+
grpc_lb_subchannel_list_unref_for_connectivity_watch(
|
426
|
+
sd->subchannel_list, "rr_connectivity_shutdown");
|
427
|
+
} else { // sd not in SHUTDOWN
|
428
|
+
if (sd->curr_connectivity_state == GRPC_CHANNEL_READY) {
|
426
429
|
if (sd->connected_subchannel == nullptr) {
|
427
|
-
sd->connected_subchannel =
|
428
|
-
grpc_subchannel_get_connected_subchannel(sd->subchannel)
|
430
|
+
sd->connected_subchannel = GRPC_CONNECTED_SUBCHANNEL_REF(
|
431
|
+
grpc_subchannel_get_connected_subchannel(sd->subchannel),
|
432
|
+
"connected");
|
429
433
|
}
|
430
434
|
if (sd->subchannel_list != p->subchannel_list) {
|
431
435
|
// promote sd->subchannel_list to p->subchannel_list.
|
@@ -468,7 +472,8 @@ static void rr_connectivity_changed_locked(void* arg, grpc_error* error) {
|
|
468
472
|
grpc_lb_policy_pick_state* pick;
|
469
473
|
while ((pick = p->pending_picks)) {
|
470
474
|
p->pending_picks = pick->next;
|
471
|
-
pick->connected_subchannel =
|
475
|
+
pick->connected_subchannel = GRPC_CONNECTED_SUBCHANNEL_REF(
|
476
|
+
selected->connected_subchannel, "rr_picked");
|
472
477
|
if (pick->user_data != nullptr) {
|
473
478
|
*pick->user_data = selected->user_data;
|
474
479
|
}
|
@@ -481,15 +486,10 @@ static void rr_connectivity_changed_locked(void* arg, grpc_error* error) {
|
|
481
486
|
}
|
482
487
|
GRPC_CLOSURE_SCHED(pick->on_complete, GRPC_ERROR_NONE);
|
483
488
|
}
|
484
|
-
break;
|
485
489
|
}
|
486
|
-
|
487
|
-
|
488
|
-
case GRPC_CHANNEL_CONNECTING:
|
489
|
-
case GRPC_CHANNEL_IDLE:; // fallthrough
|
490
|
+
// Renew notification.
|
491
|
+
grpc_lb_subchannel_data_start_connectivity_watch(sd);
|
490
492
|
}
|
491
|
-
// Renew notification.
|
492
|
-
grpc_lb_subchannel_data_start_connectivity_watch(sd);
|
493
493
|
}
|
494
494
|
|
495
495
|
static grpc_connectivity_state rr_check_connectivity_locked(
|
@@ -513,9 +513,10 @@ static void rr_ping_one_locked(grpc_lb_policy* pol, grpc_closure* on_initiate,
|
|
513
513
|
if (next_ready_index < p->subchannel_list->num_subchannels) {
|
514
514
|
grpc_lb_subchannel_data* selected =
|
515
515
|
&p->subchannel_list->subchannels[next_ready_index];
|
516
|
-
|
517
|
-
selected->connected_subchannel;
|
518
|
-
target
|
516
|
+
grpc_connected_subchannel* target = GRPC_CONNECTED_SUBCHANNEL_REF(
|
517
|
+
selected->connected_subchannel, "rr_ping");
|
518
|
+
grpc_connected_subchannel_ping(target, on_initiate, on_ack);
|
519
|
+
GRPC_CONNECTED_SUBCHANNEL_UNREF(target, "rr_ping");
|
519
520
|
} else {
|
520
521
|
GRPC_CLOSURE_SCHED(on_initiate, GRPC_ERROR_CREATE_FROM_STATIC_STRING(
|
521
522
|
"Round Robin not connected"));
|
@@ -42,7 +42,10 @@ void grpc_lb_subchannel_data_unref_subchannel(grpc_lb_subchannel_data* sd,
|
|
42
42
|
}
|
43
43
|
GRPC_SUBCHANNEL_UNREF(sd->subchannel, reason);
|
44
44
|
sd->subchannel = nullptr;
|
45
|
-
sd->connected_subchannel
|
45
|
+
if (sd->connected_subchannel != nullptr) {
|
46
|
+
GRPC_CONNECTED_SUBCHANNEL_UNREF(sd->connected_subchannel, reason);
|
47
|
+
sd->connected_subchannel = nullptr;
|
48
|
+
}
|
46
49
|
if (sd->user_data != nullptr) {
|
47
50
|
GPR_ASSERT(sd->user_data_vtable != nullptr);
|
48
51
|
sd->user_data_vtable->destroy(sd->user_data);
|
@@ -22,7 +22,6 @@
|
|
22
22
|
#include "src/core/ext/filters/client_channel/lb_policy_registry.h"
|
23
23
|
#include "src/core/ext/filters/client_channel/subchannel.h"
|
24
24
|
#include "src/core/lib/debug/trace.h"
|
25
|
-
#include "src/core/lib/gpr++/ref_counted_ptr.h"
|
26
25
|
#include "src/core/lib/transport/connectivity_state.h"
|
27
26
|
|
28
27
|
// TODO(roth): This code is intended to be shared between pick_first and
|
@@ -44,7 +43,7 @@ typedef struct {
|
|
44
43
|
grpc_lb_subchannel_list* subchannel_list;
|
45
44
|
/** subchannel itself */
|
46
45
|
grpc_subchannel* subchannel;
|
47
|
-
|
46
|
+
grpc_connected_subchannel* connected_subchannel;
|
48
47
|
/** Is a connectivity notification pending? */
|
49
48
|
bool connectivity_notification_pending;
|
50
49
|
/** notification that connectivity has changed on subchannel */
|
@@ -56,6 +56,10 @@
|
|
56
56
|
#define GRPC_SUBCHANNEL_RECONNECT_MAX_BACKOFF_SECONDS 120
|
57
57
|
#define GRPC_SUBCHANNEL_RECONNECT_JITTER 0.2
|
58
58
|
|
59
|
+
#define GET_CONNECTED_SUBCHANNEL(subchannel, barrier) \
|
60
|
+
((grpc_connected_subchannel*)(gpr_atm_##barrier##_load( \
|
61
|
+
&(subchannel)->connected_subchannel)))
|
62
|
+
|
59
63
|
namespace {
|
60
64
|
struct state_watcher {
|
61
65
|
grpc_closure closure;
|
@@ -95,7 +99,7 @@ struct grpc_subchannel {
|
|
95
99
|
grpc_connect_out_args connecting_result;
|
96
100
|
|
97
101
|
/** callback for connection finishing */
|
98
|
-
grpc_closure
|
102
|
+
grpc_closure connected;
|
99
103
|
|
100
104
|
/** callback for our alarm */
|
101
105
|
grpc_closure on_alarm;
|
@@ -104,13 +108,12 @@ struct grpc_subchannel {
|
|
104
108
|
being setup */
|
105
109
|
grpc_pollset_set* pollset_set;
|
106
110
|
|
111
|
+
/** active connection, or null; of type grpc_connected_subchannel */
|
112
|
+
gpr_atm connected_subchannel;
|
113
|
+
|
107
114
|
/** mutex protecting remaining elements */
|
108
115
|
gpr_mu mu;
|
109
116
|
|
110
|
-
/** active connection, or null; of type grpc_core::ConnectedSubchannel
|
111
|
-
*/
|
112
|
-
grpc_core::RefCountedPtr<grpc_core::ConnectedSubchannel> connected_subchannel;
|
113
|
-
|
114
117
|
/** have we seen a disconnection? */
|
115
118
|
bool disconnected;
|
116
119
|
/** are we connecting */
|
@@ -134,15 +137,16 @@ struct grpc_subchannel {
|
|
134
137
|
};
|
135
138
|
|
136
139
|
struct grpc_subchannel_call {
|
137
|
-
|
140
|
+
grpc_connected_subchannel* connection;
|
138
141
|
grpc_closure* schedule_closure_after_destroy;
|
139
142
|
};
|
140
143
|
|
141
144
|
#define SUBCHANNEL_CALL_TO_CALL_STACK(call) ((grpc_call_stack*)((call) + 1))
|
145
|
+
#define CHANNEL_STACK_FROM_CONNECTION(con) ((grpc_channel_stack*)(con))
|
142
146
|
#define CALLSTACK_TO_SUBCHANNEL_CALL(callstack) \
|
143
147
|
(((grpc_subchannel_call*)(callstack)) - 1)
|
144
148
|
|
145
|
-
static void
|
149
|
+
static void subchannel_connected(void* subchannel, grpc_error* error);
|
146
150
|
|
147
151
|
#ifndef NDEBUG
|
148
152
|
#define REF_REASON reason
|
@@ -160,9 +164,20 @@ static void on_subchannel_connected(void* subchannel, grpc_error* error);
|
|
160
164
|
*/
|
161
165
|
|
162
166
|
static void connection_destroy(void* arg, grpc_error* error) {
|
163
|
-
|
164
|
-
grpc_channel_stack_destroy(
|
165
|
-
gpr_free(
|
167
|
+
grpc_connected_subchannel* c = (grpc_connected_subchannel*)arg;
|
168
|
+
grpc_channel_stack_destroy(CHANNEL_STACK_FROM_CONNECTION(c));
|
169
|
+
gpr_free(c);
|
170
|
+
}
|
171
|
+
|
172
|
+
grpc_connected_subchannel* grpc_connected_subchannel_ref(
|
173
|
+
grpc_connected_subchannel* c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
|
174
|
+
GRPC_CHANNEL_STACK_REF(CHANNEL_STACK_FROM_CONNECTION(c), REF_REASON);
|
175
|
+
return c;
|
176
|
+
}
|
177
|
+
|
178
|
+
void grpc_connected_subchannel_unref(
|
179
|
+
grpc_connected_subchannel* c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
|
180
|
+
GRPC_CHANNEL_STACK_UNREF(CHANNEL_STACK_FROM_CONNECTION(c), REF_REASON);
|
166
181
|
}
|
167
182
|
|
168
183
|
/*
|
@@ -229,13 +244,18 @@ grpc_subchannel* grpc_subchannel_ref_from_weak_ref(
|
|
229
244
|
}
|
230
245
|
|
231
246
|
static void disconnect(grpc_subchannel* c) {
|
247
|
+
grpc_connected_subchannel* con;
|
232
248
|
grpc_subchannel_index_unregister(c->key, c);
|
233
249
|
gpr_mu_lock(&c->mu);
|
234
250
|
GPR_ASSERT(!c->disconnected);
|
235
251
|
c->disconnected = true;
|
236
252
|
grpc_connector_shutdown(c->connector, GRPC_ERROR_CREATE_FROM_STATIC_STRING(
|
237
253
|
"Subchannel disconnected"));
|
238
|
-
c
|
254
|
+
con = GET_CONNECTED_SUBCHANNEL(c, no_barrier);
|
255
|
+
if (con != nullptr) {
|
256
|
+
GRPC_CONNECTED_SUBCHANNEL_UNREF(con, "connection");
|
257
|
+
gpr_atm_no_barrier_store(&c->connected_subchannel, (gpr_atm)0xdeadbeef);
|
258
|
+
}
|
239
259
|
gpr_mu_unlock(&c->mu);
|
240
260
|
}
|
241
261
|
|
@@ -355,7 +375,7 @@ grpc_subchannel* grpc_subchannel_create(grpc_connector* connector,
|
|
355
375
|
if (new_args != nullptr) grpc_channel_args_destroy(new_args);
|
356
376
|
c->root_external_state_watcher.next = c->root_external_state_watcher.prev =
|
357
377
|
&c->root_external_state_watcher;
|
358
|
-
GRPC_CLOSURE_INIT(&c->
|
378
|
+
GRPC_CLOSURE_INIT(&c->connected, subchannel_connected, c,
|
359
379
|
grpc_schedule_on_exec_ctx);
|
360
380
|
grpc_connectivity_state_init(&c->state_tracker, GRPC_CHANNEL_IDLE,
|
361
381
|
"subchannel");
|
@@ -379,7 +399,7 @@ static void continue_connect_locked(grpc_subchannel* c) {
|
|
379
399
|
grpc_connectivity_state_set(&c->state_tracker, GRPC_CHANNEL_CONNECTING,
|
380
400
|
GRPC_ERROR_NONE, "state_change");
|
381
401
|
grpc_connector_connect(c->connector, &args, &c->connecting_result,
|
382
|
-
&c->
|
402
|
+
&c->connected);
|
383
403
|
}
|
384
404
|
|
385
405
|
grpc_connectivity_state grpc_subchannel_check_connectivity(grpc_subchannel* c,
|
@@ -439,7 +459,7 @@ static void maybe_start_connecting_locked(grpc_subchannel* c) {
|
|
439
459
|
return;
|
440
460
|
}
|
441
461
|
|
442
|
-
if (c
|
462
|
+
if (GET_CONNECTED_SUBCHANNEL(c, no_barrier) != nullptr) {
|
443
463
|
/* Already connected: don't restart */
|
444
464
|
return;
|
445
465
|
}
|
@@ -461,10 +481,9 @@ static void maybe_start_connecting_locked(grpc_subchannel* c) {
|
|
461
481
|
const grpc_millis time_til_next =
|
462
482
|
c->next_attempt_deadline - grpc_core::ExecCtx::Get()->Now();
|
463
483
|
if (time_til_next <= 0) {
|
464
|
-
gpr_log(GPR_INFO, "
|
484
|
+
gpr_log(GPR_INFO, "Retry immediately");
|
465
485
|
} else {
|
466
|
-
gpr_log(GPR_INFO, "
|
467
|
-
time_til_next);
|
486
|
+
gpr_log(GPR_INFO, "Retry in %" PRIdPTR " milliseconds", time_til_next);
|
468
487
|
}
|
469
488
|
GRPC_CLOSURE_INIT(&c->on_alarm, on_alarm, c, grpc_schedule_on_exec_ctx);
|
470
489
|
grpc_timer_init(&c->alarm, c->next_attempt_deadline, &c->on_alarm);
|
@@ -508,56 +527,75 @@ void grpc_subchannel_notify_on_state_change(
|
|
508
527
|
}
|
509
528
|
}
|
510
529
|
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
530
|
+
void grpc_connected_subchannel_process_transport_op(
|
531
|
+
grpc_connected_subchannel* con, grpc_transport_op* op) {
|
532
|
+
grpc_channel_stack* channel_stack = CHANNEL_STACK_FROM_CONNECTION(con);
|
533
|
+
grpc_channel_element* top_elem = grpc_channel_stack_element(channel_stack, 0);
|
534
|
+
top_elem->filter->start_transport_op(top_elem, op);
|
535
|
+
}
|
536
|
+
|
537
|
+
static void subchannel_on_child_state_changed(void* p, grpc_error* error) {
|
538
|
+
state_watcher* sw = (state_watcher*)p;
|
539
|
+
grpc_subchannel* c = sw->subchannel;
|
515
540
|
gpr_mu* mu = &c->mu;
|
516
541
|
|
517
542
|
gpr_mu_lock(mu);
|
518
543
|
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
grpc_connectivity_state_set(&c->state_tracker,
|
533
|
-
GRPC_CHANNEL_TRANSIENT_FAILURE,
|
534
|
-
GRPC_ERROR_REF(error), "reflect_child");
|
535
|
-
c->backoff_begun = false;
|
536
|
-
c->backoff->Reset();
|
537
|
-
maybe_start_connecting_locked(c);
|
538
|
-
} else {
|
539
|
-
connected_subchannel_watcher->connectivity_state =
|
540
|
-
GRPC_CHANNEL_SHUTDOWN;
|
541
|
-
}
|
542
|
-
break;
|
543
|
-
}
|
544
|
-
default: {
|
545
|
-
grpc_connectivity_state_set(
|
546
|
-
&c->state_tracker, connected_subchannel_watcher->connectivity_state,
|
547
|
-
GRPC_ERROR_REF(error), "reflect_child");
|
548
|
-
GRPC_SUBCHANNEL_WEAK_REF(c, "state_watcher");
|
549
|
-
c->connected_subchannel->NotifyOnStateChange(
|
550
|
-
nullptr, &connected_subchannel_watcher->connectivity_state,
|
551
|
-
&connected_subchannel_watcher->closure);
|
552
|
-
connected_subchannel_watcher = nullptr;
|
553
|
-
}
|
544
|
+
/* if we failed just leave this closure */
|
545
|
+
if (sw->connectivity_state == GRPC_CHANNEL_TRANSIENT_FAILURE) {
|
546
|
+
/* any errors on a subchannel ==> we're done, create a new one */
|
547
|
+
sw->connectivity_state = GRPC_CHANNEL_SHUTDOWN;
|
548
|
+
}
|
549
|
+
grpc_connectivity_state_set(&c->state_tracker, sw->connectivity_state,
|
550
|
+
GRPC_ERROR_REF(error), "reflect_child");
|
551
|
+
if (sw->connectivity_state != GRPC_CHANNEL_SHUTDOWN) {
|
552
|
+
grpc_connected_subchannel_notify_on_state_change(
|
553
|
+
GET_CONNECTED_SUBCHANNEL(c, no_barrier), nullptr,
|
554
|
+
&sw->connectivity_state, &sw->closure);
|
555
|
+
GRPC_SUBCHANNEL_WEAK_REF(c, "state_watcher");
|
556
|
+
sw = nullptr;
|
554
557
|
}
|
558
|
+
|
555
559
|
gpr_mu_unlock(mu);
|
556
560
|
GRPC_SUBCHANNEL_WEAK_UNREF(c, "state_watcher");
|
557
|
-
gpr_free(
|
561
|
+
gpr_free(sw);
|
562
|
+
}
|
563
|
+
|
564
|
+
static void connected_subchannel_state_op(grpc_connected_subchannel* con,
|
565
|
+
grpc_pollset_set* interested_parties,
|
566
|
+
grpc_connectivity_state* state,
|
567
|
+
grpc_closure* closure) {
|
568
|
+
grpc_transport_op* op = grpc_make_transport_op(nullptr);
|
569
|
+
grpc_channel_element* elem;
|
570
|
+
op->connectivity_state = state;
|
571
|
+
op->on_connectivity_state_change = closure;
|
572
|
+
op->bind_pollset_set = interested_parties;
|
573
|
+
elem = grpc_channel_stack_element(CHANNEL_STACK_FROM_CONNECTION(con), 0);
|
574
|
+
elem->filter->start_transport_op(elem, op);
|
575
|
+
}
|
576
|
+
|
577
|
+
void grpc_connected_subchannel_notify_on_state_change(
|
578
|
+
grpc_connected_subchannel* con, grpc_pollset_set* interested_parties,
|
579
|
+
grpc_connectivity_state* state, grpc_closure* closure) {
|
580
|
+
connected_subchannel_state_op(con, interested_parties, state, closure);
|
581
|
+
}
|
582
|
+
|
583
|
+
void grpc_connected_subchannel_ping(grpc_connected_subchannel* con,
|
584
|
+
grpc_closure* on_initiate,
|
585
|
+
grpc_closure* on_ack) {
|
586
|
+
grpc_transport_op* op = grpc_make_transport_op(nullptr);
|
587
|
+
grpc_channel_element* elem;
|
588
|
+
op->send_ping.on_initiate = on_initiate;
|
589
|
+
op->send_ping.on_ack = on_ack;
|
590
|
+
elem = grpc_channel_stack_element(CHANNEL_STACK_FROM_CONNECTION(con), 0);
|
591
|
+
elem->filter->start_transport_op(elem, op);
|
558
592
|
}
|
559
593
|
|
560
594
|
static bool publish_transport_locked(grpc_subchannel* c) {
|
595
|
+
grpc_connected_subchannel* con;
|
596
|
+
grpc_channel_stack* stk;
|
597
|
+
state_watcher* sw_subchannel;
|
598
|
+
|
561
599
|
/* construct channel stack */
|
562
600
|
grpc_channel_stack_builder* builder = grpc_channel_stack_builder_create();
|
563
601
|
grpc_channel_stack_builder_set_channel_arguments(
|
@@ -569,9 +607,8 @@ static bool publish_transport_locked(grpc_subchannel* c) {
|
|
569
607
|
grpc_channel_stack_builder_destroy(builder);
|
570
608
|
return false;
|
571
609
|
}
|
572
|
-
grpc_channel_stack* stk;
|
573
610
|
grpc_error* error = grpc_channel_stack_builder_finish(
|
574
|
-
builder, 0, 1, connection_destroy, nullptr, (void**)&
|
611
|
+
builder, 0, 1, connection_destroy, nullptr, (void**)&con);
|
575
612
|
if (error != GRPC_ERROR_NONE) {
|
576
613
|
grpc_transport_destroy(c->connecting_result.transport);
|
577
614
|
gpr_log(GPR_ERROR, "error initializing subchannel stack: %s",
|
@@ -579,37 +616,38 @@ static bool publish_transport_locked(grpc_subchannel* c) {
|
|
579
616
|
GRPC_ERROR_UNREF(error);
|
580
617
|
return false;
|
581
618
|
}
|
619
|
+
stk = CHANNEL_STACK_FROM_CONNECTION(con);
|
582
620
|
memset(&c->connecting_result, 0, sizeof(c->connecting_result));
|
583
621
|
|
584
622
|
/* initialize state watcher */
|
585
|
-
state_watcher*
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
on_connected_subchannel_connectivity_changed,
|
591
|
-
connected_subchannel_watcher, grpc_schedule_on_exec_ctx);
|
623
|
+
sw_subchannel = (state_watcher*)gpr_malloc(sizeof(*sw_subchannel));
|
624
|
+
sw_subchannel->subchannel = c;
|
625
|
+
sw_subchannel->connectivity_state = GRPC_CHANNEL_READY;
|
626
|
+
GRPC_CLOSURE_INIT(&sw_subchannel->closure, subchannel_on_child_state_changed,
|
627
|
+
sw_subchannel, grpc_schedule_on_exec_ctx);
|
592
628
|
|
593
629
|
if (c->disconnected) {
|
594
|
-
gpr_free(
|
630
|
+
gpr_free(sw_subchannel);
|
595
631
|
grpc_channel_stack_destroy(stk);
|
596
|
-
gpr_free(
|
632
|
+
gpr_free(con);
|
597
633
|
return false;
|
598
634
|
}
|
599
635
|
|
600
636
|
/* publish */
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
637
|
+
/* TODO(ctiller): this full barrier seems to clear up a TSAN failure.
|
638
|
+
I'd have expected the rel_cas below to be enough, but
|
639
|
+
seemingly it's not.
|
640
|
+
Re-evaluate if we really need this. */
|
641
|
+
gpr_atm_full_barrier();
|
642
|
+
GPR_ASSERT(gpr_atm_rel_cas(&c->connected_subchannel, 0, (gpr_atm)con));
|
605
643
|
|
606
644
|
/* setup subchannel watching connected subchannel for changes; subchannel
|
607
645
|
ref for connecting is donated to the state watcher */
|
608
646
|
GRPC_SUBCHANNEL_WEAK_REF(c, "state_watcher");
|
609
647
|
GRPC_SUBCHANNEL_WEAK_UNREF(c, "connecting");
|
610
|
-
|
611
|
-
c->pollset_set, &
|
612
|
-
&
|
648
|
+
grpc_connected_subchannel_notify_on_state_change(
|
649
|
+
con, c->pollset_set, &sw_subchannel->connectivity_state,
|
650
|
+
&sw_subchannel->closure);
|
613
651
|
|
614
652
|
/* signal completion */
|
615
653
|
grpc_connectivity_state_set(&c->state_tracker, GRPC_CHANNEL_READY,
|
@@ -617,11 +655,11 @@ static bool publish_transport_locked(grpc_subchannel* c) {
|
|
617
655
|
return true;
|
618
656
|
}
|
619
657
|
|
620
|
-
static void
|
658
|
+
static void subchannel_connected(void* arg, grpc_error* error) {
|
621
659
|
grpc_subchannel* c = (grpc_subchannel*)arg;
|
622
660
|
grpc_channel_args* delete_channel_args = c->connecting_result.channel_args;
|
623
661
|
|
624
|
-
GRPC_SUBCHANNEL_WEAK_REF(c, "
|
662
|
+
GRPC_SUBCHANNEL_WEAK_REF(c, "connected");
|
625
663
|
gpr_mu_lock(&c->mu);
|
626
664
|
c->connecting = false;
|
627
665
|
if (c->connecting_result.transport != nullptr &&
|
@@ -656,10 +694,10 @@ static void subchannel_call_destroy(void* call, grpc_error* error) {
|
|
656
694
|
grpc_subchannel_call* c = (grpc_subchannel_call*)call;
|
657
695
|
GPR_ASSERT(c->schedule_closure_after_destroy != nullptr);
|
658
696
|
GPR_TIMER_BEGIN("grpc_subchannel_call_unref.destroy", 0);
|
659
|
-
|
697
|
+
grpc_connected_subchannel* connection = c->connection;
|
660
698
|
grpc_call_stack_destroy(SUBCHANNEL_CALL_TO_CALL_STACK(c), nullptr,
|
661
699
|
c->schedule_closure_after_destroy);
|
662
|
-
connection
|
700
|
+
GRPC_CONNECTED_SUBCHANNEL_UNREF(connection, "subchannel_call");
|
663
701
|
GPR_TIMER_END("grpc_subchannel_call_unref.destroy", 0);
|
664
702
|
}
|
665
703
|
|
@@ -690,12 +728,9 @@ void grpc_subchannel_call_process_op(grpc_subchannel_call* call,
|
|
690
728
|
GPR_TIMER_END("grpc_subchannel_call_process_op", 0);
|
691
729
|
}
|
692
730
|
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
auto copy = c->connected_subchannel;
|
697
|
-
gpr_mu_unlock(&c->mu);
|
698
|
-
return copy;
|
731
|
+
grpc_connected_subchannel* grpc_subchannel_get_connected_subchannel(
|
732
|
+
grpc_subchannel* c) {
|
733
|
+
return GET_CONNECTED_SUBCHANNEL(c, acq);
|
699
734
|
}
|
700
735
|
|
701
736
|
const grpc_subchannel_key* grpc_subchannel_get_key(
|
@@ -703,6 +738,36 @@ const grpc_subchannel_key* grpc_subchannel_get_key(
|
|
703
738
|
return subchannel->key;
|
704
739
|
}
|
705
740
|
|
741
|
+
grpc_error* grpc_connected_subchannel_create_call(
|
742
|
+
grpc_connected_subchannel* con,
|
743
|
+
const grpc_connected_subchannel_call_args* args,
|
744
|
+
grpc_subchannel_call** call) {
|
745
|
+
grpc_channel_stack* chanstk = CHANNEL_STACK_FROM_CONNECTION(con);
|
746
|
+
*call = (grpc_subchannel_call*)gpr_arena_alloc(
|
747
|
+
args->arena, sizeof(grpc_subchannel_call) + chanstk->call_stack_size);
|
748
|
+
grpc_call_stack* callstk = SUBCHANNEL_CALL_TO_CALL_STACK(*call);
|
749
|
+
(*call)->connection = GRPC_CONNECTED_SUBCHANNEL_REF(con, "subchannel_call");
|
750
|
+
const grpc_call_element_args call_args = {
|
751
|
+
callstk, /* call_stack */
|
752
|
+
nullptr, /* server_transport_data */
|
753
|
+
args->context, /* context */
|
754
|
+
args->path, /* path */
|
755
|
+
args->start_time, /* start_time */
|
756
|
+
args->deadline, /* deadline */
|
757
|
+
args->arena, /* arena */
|
758
|
+
args->call_combiner /* call_combiner */
|
759
|
+
};
|
760
|
+
grpc_error* error = grpc_call_stack_init(chanstk, 1, subchannel_call_destroy,
|
761
|
+
*call, &call_args);
|
762
|
+
if (error != GRPC_ERROR_NONE) {
|
763
|
+
const char* error_string = grpc_error_string(error);
|
764
|
+
gpr_log(GPR_ERROR, "error: %s", error_string);
|
765
|
+
return error;
|
766
|
+
}
|
767
|
+
grpc_call_stack_set_pollset_or_pollset_set(callstk, args->pollent);
|
768
|
+
return GRPC_ERROR_NONE;
|
769
|
+
}
|
770
|
+
|
706
771
|
grpc_call_stack* grpc_subchannel_call_get_call_stack(
|
707
772
|
grpc_subchannel_call* subchannel_call) {
|
708
773
|
return SUBCHANNEL_CALL_TO_CALL_STACK(subchannel_call);
|
@@ -738,64 +803,3 @@ grpc_arg grpc_create_subchannel_address_arg(const grpc_resolved_address* addr) {
|
|
738
803
|
(char*)GRPC_ARG_SUBCHANNEL_ADDRESS,
|
739
804
|
addr->len > 0 ? grpc_sockaddr_to_uri(addr) : gpr_strdup(""));
|
740
805
|
}
|
741
|
-
|
742
|
-
namespace grpc_core {
|
743
|
-
ConnectedSubchannel::ConnectedSubchannel(grpc_channel_stack* channel_stack)
|
744
|
-
: grpc_core::RefCountedWithTracing(&grpc_trace_stream_refcount),
|
745
|
-
channel_stack_(channel_stack) {}
|
746
|
-
|
747
|
-
ConnectedSubchannel::~ConnectedSubchannel() {
|
748
|
-
GRPC_CHANNEL_STACK_UNREF(channel_stack_, "connected_subchannel_dtor");
|
749
|
-
}
|
750
|
-
|
751
|
-
void ConnectedSubchannel::NotifyOnStateChange(
|
752
|
-
grpc_pollset_set* interested_parties, grpc_connectivity_state* state,
|
753
|
-
grpc_closure* closure) {
|
754
|
-
grpc_transport_op* op = grpc_make_transport_op(nullptr);
|
755
|
-
grpc_channel_element* elem;
|
756
|
-
op->connectivity_state = state;
|
757
|
-
op->on_connectivity_state_change = closure;
|
758
|
-
op->bind_pollset_set = interested_parties;
|
759
|
-
elem = grpc_channel_stack_element(channel_stack_, 0);
|
760
|
-
elem->filter->start_transport_op(elem, op);
|
761
|
-
}
|
762
|
-
|
763
|
-
void ConnectedSubchannel::Ping(grpc_closure* on_initiate,
|
764
|
-
grpc_closure* on_ack) {
|
765
|
-
grpc_transport_op* op = grpc_make_transport_op(nullptr);
|
766
|
-
grpc_channel_element* elem;
|
767
|
-
op->send_ping.on_initiate = on_initiate;
|
768
|
-
op->send_ping.on_ack = on_ack;
|
769
|
-
elem = grpc_channel_stack_element(channel_stack_, 0);
|
770
|
-
elem->filter->start_transport_op(elem, op);
|
771
|
-
}
|
772
|
-
|
773
|
-
grpc_error* ConnectedSubchannel::CreateCall(const CallArgs& args,
|
774
|
-
grpc_subchannel_call** call) {
|
775
|
-
*call = (grpc_subchannel_call*)gpr_arena_alloc(
|
776
|
-
args.arena,
|
777
|
-
sizeof(grpc_subchannel_call) + channel_stack_->call_stack_size);
|
778
|
-
grpc_call_stack* callstk = SUBCHANNEL_CALL_TO_CALL_STACK(*call);
|
779
|
-
Ref(DEBUG_LOCATION, "subchannel_call");
|
780
|
-
(*call)->connection = this;
|
781
|
-
const grpc_call_element_args call_args = {
|
782
|
-
callstk, /* call_stack */
|
783
|
-
nullptr, /* server_transport_data */
|
784
|
-
args.context, /* context */
|
785
|
-
args.path, /* path */
|
786
|
-
args.start_time, /* start_time */
|
787
|
-
args.deadline, /* deadline */
|
788
|
-
args.arena, /* arena */
|
789
|
-
args.call_combiner /* call_combiner */
|
790
|
-
};
|
791
|
-
grpc_error* error = grpc_call_stack_init(
|
792
|
-
channel_stack_, 1, subchannel_call_destroy, *call, &call_args);
|
793
|
-
if (error != GRPC_ERROR_NONE) {
|
794
|
-
const char* error_string = grpc_error_string(error);
|
795
|
-
gpr_log(GPR_ERROR, "error: %s", error_string);
|
796
|
-
return error;
|
797
|
-
}
|
798
|
-
grpc_call_stack_set_pollset_or_pollset_set(callstk, args.pollent);
|
799
|
-
return GRPC_ERROR_NONE;
|
800
|
-
}
|
801
|
-
} // namespace grpc_core
|
@@ -34,6 +34,7 @@
|
|
34
34
|
/** A (sub-)channel that knows how to connect to exactly one target
|
35
35
|
address. Provides a target for load balancing. */
|
36
36
|
typedef struct grpc_subchannel grpc_subchannel;
|
37
|
+
typedef struct grpc_connected_subchannel grpc_connected_subchannel;
|
37
38
|
typedef struct grpc_subchannel_call grpc_subchannel_call;
|
38
39
|
typedef struct grpc_subchannel_args grpc_subchannel_args;
|
39
40
|
typedef struct grpc_subchannel_key grpc_subchannel_key;
|
@@ -49,6 +50,10 @@ typedef struct grpc_subchannel_key grpc_subchannel_key;
|
|
49
50
|
grpc_subchannel_weak_ref((p), __FILE__, __LINE__, (r))
|
50
51
|
#define GRPC_SUBCHANNEL_WEAK_UNREF(p, r) \
|
51
52
|
grpc_subchannel_weak_unref((p), __FILE__, __LINE__, (r))
|
53
|
+
#define GRPC_CONNECTED_SUBCHANNEL_REF(p, r) \
|
54
|
+
grpc_connected_subchannel_ref((p), __FILE__, __LINE__, (r))
|
55
|
+
#define GRPC_CONNECTED_SUBCHANNEL_UNREF(p, r) \
|
56
|
+
grpc_connected_subchannel_unref((p), __FILE__, __LINE__, (r))
|
52
57
|
#define GRPC_SUBCHANNEL_CALL_REF(p, r) \
|
53
58
|
grpc_subchannel_call_ref((p), __FILE__, __LINE__, (r))
|
54
59
|
#define GRPC_SUBCHANNEL_CALL_UNREF(p, r) \
|
@@ -62,39 +67,14 @@ typedef struct grpc_subchannel_key grpc_subchannel_key;
|
|
62
67
|
#define GRPC_SUBCHANNEL_UNREF(p, r) grpc_subchannel_unref((p))
|
63
68
|
#define GRPC_SUBCHANNEL_WEAK_REF(p, r) grpc_subchannel_weak_ref((p))
|
64
69
|
#define GRPC_SUBCHANNEL_WEAK_UNREF(p, r) grpc_subchannel_weak_unref((p))
|
70
|
+
#define GRPC_CONNECTED_SUBCHANNEL_REF(p, r) grpc_connected_subchannel_ref((p))
|
71
|
+
#define GRPC_CONNECTED_SUBCHANNEL_UNREF(p, r) \
|
72
|
+
grpc_connected_subchannel_unref((p))
|
65
73
|
#define GRPC_SUBCHANNEL_CALL_REF(p, r) grpc_subchannel_call_ref((p))
|
66
74
|
#define GRPC_SUBCHANNEL_CALL_UNREF(p, r) grpc_subchannel_call_unref((p))
|
67
75
|
#define GRPC_SUBCHANNEL_REF_EXTRA_ARGS
|
68
76
|
#endif
|
69
77
|
|
70
|
-
namespace grpc_core {
|
71
|
-
class ConnectedSubchannel : public grpc_core::RefCountedWithTracing {
|
72
|
-
public:
|
73
|
-
struct CallArgs {
|
74
|
-
grpc_polling_entity* pollent;
|
75
|
-
grpc_slice path;
|
76
|
-
gpr_timespec start_time;
|
77
|
-
grpc_millis deadline;
|
78
|
-
gpr_arena* arena;
|
79
|
-
grpc_call_context_element* context;
|
80
|
-
grpc_call_combiner* call_combiner;
|
81
|
-
};
|
82
|
-
|
83
|
-
explicit ConnectedSubchannel(grpc_channel_stack* channel_stack);
|
84
|
-
~ConnectedSubchannel();
|
85
|
-
|
86
|
-
grpc_channel_stack* channel_stack() { return channel_stack_; }
|
87
|
-
void NotifyOnStateChange(grpc_pollset_set* interested_parties,
|
88
|
-
grpc_connectivity_state* state,
|
89
|
-
grpc_closure* closure);
|
90
|
-
void Ping(grpc_closure* on_initiate, grpc_closure* on_ack);
|
91
|
-
grpc_error* CreateCall(const CallArgs& args, grpc_subchannel_call** call);
|
92
|
-
|
93
|
-
private:
|
94
|
-
grpc_channel_stack* channel_stack_;
|
95
|
-
};
|
96
|
-
} // namespace grpc_core
|
97
|
-
|
98
78
|
grpc_subchannel* grpc_subchannel_ref(
|
99
79
|
grpc_subchannel* channel GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
|
100
80
|
grpc_subchannel* grpc_subchannel_ref_from_weak_ref(
|
@@ -105,11 +85,35 @@ grpc_subchannel* grpc_subchannel_weak_ref(
|
|
105
85
|
grpc_subchannel* channel GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
|
106
86
|
void grpc_subchannel_weak_unref(
|
107
87
|
grpc_subchannel* channel GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
|
88
|
+
grpc_connected_subchannel* grpc_connected_subchannel_ref(
|
89
|
+
grpc_connected_subchannel* channel GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
|
90
|
+
void grpc_connected_subchannel_unref(
|
91
|
+
grpc_connected_subchannel* channel GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
|
108
92
|
void grpc_subchannel_call_ref(
|
109
93
|
grpc_subchannel_call* call GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
|
110
94
|
void grpc_subchannel_call_unref(
|
111
95
|
grpc_subchannel_call* call GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
|
112
96
|
|
97
|
+
/** construct a subchannel call */
|
98
|
+
typedef struct {
|
99
|
+
grpc_polling_entity* pollent;
|
100
|
+
grpc_slice path;
|
101
|
+
gpr_timespec start_time;
|
102
|
+
grpc_millis deadline;
|
103
|
+
gpr_arena* arena;
|
104
|
+
grpc_call_context_element* context;
|
105
|
+
grpc_call_combiner* call_combiner;
|
106
|
+
} grpc_connected_subchannel_call_args;
|
107
|
+
|
108
|
+
grpc_error* grpc_connected_subchannel_create_call(
|
109
|
+
grpc_connected_subchannel* connected_subchannel,
|
110
|
+
const grpc_connected_subchannel_call_args* args,
|
111
|
+
grpc_subchannel_call** subchannel_call);
|
112
|
+
|
113
|
+
/** process a transport level op */
|
114
|
+
void grpc_connected_subchannel_process_transport_op(
|
115
|
+
grpc_connected_subchannel* subchannel, grpc_transport_op* op);
|
116
|
+
|
113
117
|
/** poll the current connectivity state of a channel */
|
114
118
|
grpc_connectivity_state grpc_subchannel_check_connectivity(
|
115
119
|
grpc_subchannel* channel, grpc_error** error);
|
@@ -119,12 +123,17 @@ grpc_connectivity_state grpc_subchannel_check_connectivity(
|
|
119
123
|
void grpc_subchannel_notify_on_state_change(
|
120
124
|
grpc_subchannel* channel, grpc_pollset_set* interested_parties,
|
121
125
|
grpc_connectivity_state* state, grpc_closure* notify);
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
*
|
126
|
-
|
127
|
-
|
126
|
+
void grpc_connected_subchannel_notify_on_state_change(
|
127
|
+
grpc_connected_subchannel* channel, grpc_pollset_set* interested_parties,
|
128
|
+
grpc_connectivity_state* state, grpc_closure* notify);
|
129
|
+
void grpc_connected_subchannel_ping(grpc_connected_subchannel* channel,
|
130
|
+
grpc_closure* on_initiate,
|
131
|
+
grpc_closure* on_ack);
|
132
|
+
|
133
|
+
/** retrieve the grpc_connected_subchannel - or NULL if called before
|
134
|
+
the subchannel becomes connected */
|
135
|
+
grpc_connected_subchannel* grpc_subchannel_get_connected_subchannel(
|
136
|
+
grpc_subchannel* subchannel);
|
128
137
|
|
129
138
|
/** return the subchannel index key for \a subchannel */
|
130
139
|
const grpc_subchannel_key* grpc_subchannel_get_key(
|
@@ -1081,6 +1081,7 @@ static grpc_stream_compression_algorithm decode_stream_compression(
|
|
1081
1081
|
static void publish_app_metadata(grpc_call* call, grpc_metadata_batch* b,
|
1082
1082
|
int is_trailing) {
|
1083
1083
|
if (b->list.count == 0) return;
|
1084
|
+
if (is_trailing && call->buffered_metadata[1] == nullptr) return;
|
1084
1085
|
GPR_TIMER_BEGIN("publish_app_metadata", 0);
|
1085
1086
|
grpc_metadata_array* dest;
|
1086
1087
|
grpc_metadata* mdusr;
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: grpc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.9.0.
|
4
|
+
version: 1.9.0.pre3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- gRPC Authors
|
8
8
|
autorequire:
|
9
9
|
bindir: src/ruby/bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-01-
|
11
|
+
date: 2018-01-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: google-protobuf
|