aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h
blob: e18ad490e8e97fcf6c1a0ac2cd707db933ec20f4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/*
 *
 * Copyright 2015 gRPC authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_SUBCHANNEL_LIST_H
#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_SUBCHANNEL_LIST_H

#include "src/core/ext/filters/client_channel/lb_policy_registry.h"
#include "src/core/ext/filters/client_channel/subchannel.h"
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/transport/connectivity_state.h"

// TODO(roth): This code is intended to be shared between pick_first and
// round_robin.  However, the interface needs more work to provide clean
// encapsulation.  For example, the structs here have some fields that are
// only used in one of the two (e.g., the state counters in
// grpc_lb_subchannel_list and the prev_connectivity_state field in
// grpc_lb_subchannel_data are only used in round_robin, and the
// checking_subchannel field in grpc_lb_subchannel_list is only used by
// pick_first).  Also, there is probably some code duplication between the
// connectivity state notification callback code in both pick_first and
// round_robin that could be refactored and moved here.  In a future PR,
// need to clean this up.

#ifdef __cplusplus
extern "C" {
#endif

typedef struct grpc_lb_subchannel_list grpc_lb_subchannel_list;

typedef struct {
  /** backpointer to owning subchannel list */
  grpc_lb_subchannel_list* subchannel_list;
  /** subchannel itself */
  grpc_subchannel* subchannel;
  grpc_connected_subchannel* connected_subchannel;
  /** Is a connectivity notification pending? */
  bool connectivity_notification_pending;
  /** notification that connectivity has changed on subchannel */
  grpc_closure connectivity_changed_closure;
  /** previous and current connectivity states.  Updated by \a
   * \a connectivity_changed_closure based on
   * \a pending_connectivity_state_unsafe. */
  grpc_connectivity_state prev_connectivity_state;
  grpc_connectivity_state curr_connectivity_state;
  /** connectivity state to be updated by
   * grpc_subchannel_notify_on_state_change(), not guarded by
   * the combiner.  To be copied to \a curr_connectivity_state by
   * \a connectivity_changed_closure. */
  grpc_connectivity_state pending_connectivity_state_unsafe;
  /** the subchannel's target user data */
  void* user_data;
  /** vtable to operate over \a user_data */
  const grpc_lb_user_data_vtable* user_data_vtable;
} grpc_lb_subchannel_data;

/// Unrefs the subchannel contained in sd.
void grpc_lb_subchannel_data_unref_subchannel(grpc_exec_ctx* exec_ctx,
                                              grpc_lb_subchannel_data* sd,
                                              const char* reason);

/// Starts watching the connectivity state of the subchannel.
/// The connectivity_changed_cb callback must invoke either
/// grpc_lb_subchannel_data_stop_connectivity_watch() or again call
/// grpc_lb_subchannel_data_start_connectivity_watch().
void grpc_lb_subchannel_data_start_connectivity_watch(
    grpc_exec_ctx* exec_ctx, grpc_lb_subchannel_data* sd);

/// Stops watching the connectivity state of the subchannel.
void grpc_lb_subchannel_data_stop_connectivity_watch(
    grpc_exec_ctx* exec_ctx, grpc_lb_subchannel_data* sd);

struct grpc_lb_subchannel_list {
  /** backpointer to owning policy */
  grpc_lb_policy* policy;

  grpc_tracer_flag* tracer;

  /** all our subchannels */
  size_t num_subchannels;
  grpc_lb_subchannel_data* subchannels;

  /** Index into subchannels of the one we're currently checking.
   * Used when connecting to subchannels serially instead of in parallel. */
  // TODO(roth): When we have time, we can probably make this go away
  // and compute the index dynamically by subtracting
  // subchannel_list->subchannels from the subchannel_data pointer.
  size_t checking_subchannel;

  /** how many subchannels are in state READY */
  size_t num_ready;
  /** how many subchannels are in state TRANSIENT_FAILURE */
  size_t num_transient_failures;
  /** how many subchannels are in state SHUTDOWN */
  size_t num_shutdown;
  /** how many subchannels are in state IDLE */
  size_t num_idle;

  /** There will be one ref for each entry in subchannels for which there is a
   * pending connectivity state watcher callback. */
  gpr_refcount refcount;

  /** Is this list shutting down? This may be true due to the shutdown of the
   * policy itself or because a newer update has arrived while this one hadn't
   * finished processing. */
  bool shutting_down;
};

grpc_lb_subchannel_list* grpc_lb_subchannel_list_create(
    grpc_exec_ctx* exec_ctx, grpc_lb_policy* p, grpc_tracer_flag* tracer,
    const grpc_lb_addresses* addresses, const grpc_lb_policy_args* args,
    grpc_iomgr_cb_func connectivity_changed_cb);

void grpc_lb_subchannel_list_ref(grpc_lb_subchannel_list* subchannel_list,
                                 const char* reason);

void grpc_lb_subchannel_list_unref(grpc_exec_ctx* exec_ctx,
                                   grpc_lb_subchannel_list* subchannel_list,
                                   const char* reason);

/// Takes and releases refs needed for a connectivity notification.
/// This includes a ref to subchannel_list and a weak ref to the LB policy.
void grpc_lb_subchannel_list_ref_for_connectivity_watch(
    grpc_lb_subchannel_list* subchannel_list, const char* reason);
void grpc_lb_subchannel_list_unref_for_connectivity_watch(
    grpc_exec_ctx* exec_ctx, grpc_lb_subchannel_list* subchannel_list,
    const char* reason);

/// Mark subchannel_list as discarded. Unsubscribes all its subchannels. The
/// connectivity state notification callback will ultimately unref it.
void grpc_lb_subchannel_list_shutdown_and_unref(
    grpc_exec_ctx* exec_ctx, grpc_lb_subchannel_list* subchannel_list,
    const char* reason);

#ifdef __cplusplus
}
#endif

#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_SUBCHANNEL_LIST_H */