• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

grpc / grpc-java / #20349

07 Jul 2026 10:24AM UTC coverage: 89.111% (-0.01%) from 89.122%
#20349

push

github

web-flow
enable child channel plugins (#12578)

Implements https://github.com/grpc/proposal/pull/529

38030 of 42677 relevant lines covered (89.11%)

0.89 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.43
/../xds/src/main/java/io/grpc/xds/SharedXdsClientPoolProvider.java
1
/*
2
 * Copyright 2020 The gRPC Authors
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16

17
package io.grpc.xds;
18

19
import static com.google.common.base.Preconditions.checkNotNull;
20

21
import com.google.common.annotations.VisibleForTesting;
22
import com.google.common.collect.ImmutableList;
23
import com.google.errorprone.annotations.concurrent.GuardedBy;
24
import io.grpc.CallCredentials;
25
import io.grpc.ChannelConfigurator;
26
import io.grpc.MetricRecorder;
27
import io.grpc.internal.ExponentialBackoffPolicy;
28
import io.grpc.internal.GrpcUtil;
29
import io.grpc.internal.ObjectPool;
30
import io.grpc.internal.SharedResourceHolder;
31
import io.grpc.internal.TimeProvider;
32
import io.grpc.xds.client.Bootstrapper;
33
import io.grpc.xds.client.Bootstrapper.BootstrapInfo;
34
import io.grpc.xds.client.XdsClient;
35
import io.grpc.xds.client.XdsClientImpl;
36
import io.grpc.xds.client.XdsInitializationException;
37
import io.grpc.xds.internal.security.TlsContextManagerImpl;
38
import java.util.Map;
39
import java.util.concurrent.ConcurrentHashMap;
40
import java.util.concurrent.ScheduledExecutorService;
41
import java.util.logging.Level;
42
import java.util.logging.Logger;
43
import javax.annotation.Nullable;
44
import javax.annotation.concurrent.ThreadSafe;
45

46
/**
47
 * The global factory for creating a singleton {@link XdsClient} instance to be used by all gRPC
48
 * clients in the process.
49
 */
50
@ThreadSafe
51
final class SharedXdsClientPoolProvider implements XdsClientPoolFactory {
52
  private static final boolean LOG_XDS_NODE_ID = Boolean.parseBoolean(
1✔
53
      System.getenv("GRPC_LOG_XDS_NODE_ID"));
1✔
54
  private static final Logger log = Logger.getLogger(XdsClientImpl.class.getName());
1✔
55
  private static final ExponentialBackoffPolicy.Provider BACKOFF_POLICY_PROVIDER =
1✔
56
      new ExponentialBackoffPolicy.Provider();
57

58
  @Nullable
59
  private final Bootstrapper bootstrapper;
60
  private final Object lock = new Object();
1✔
61
  /*
62
     The first one wins.
63
     Anything with the same target string uses the client created for the first one.
64
  */
65
  private final Map<String, ObjectPool<XdsClient>> targetToXdsClientMap = new ConcurrentHashMap<>();
1✔
66

67
  SharedXdsClientPoolProvider() {
68
    this(null);
1✔
69
  }
1✔
70

71
  @VisibleForTesting
72
  SharedXdsClientPoolProvider(@Nullable Bootstrapper bootstrapper) {
1✔
73
    this.bootstrapper = bootstrapper;
1✔
74
  }
1✔
75

76
  static SharedXdsClientPoolProvider getDefaultProvider() {
77
    return SharedXdsClientPoolProviderHolder.instance;
1✔
78
  }
79

80
  @Override
81
  @Nullable
82
  public ObjectPool<XdsClient> get(String target) {
83
    return targetToXdsClientMap.get(target);
1✔
84
  }
85

86
  @Deprecated
87
  public ObjectPool<XdsClient> getOrCreate(
88
      String target, MetricRecorder metricRecorder, CallCredentials transportCallCredentials)
89
      throws XdsInitializationException {
90
    BootstrapInfo bootstrapInfo;
91
    if (bootstrapper != null) {
1✔
92
      bootstrapInfo = bootstrapper.bootstrap();
1✔
93
    } else {
94
      bootstrapInfo = GrpcBootstrapperImpl.defaultBootstrap();
×
95
    }
96
    return getOrCreate(target, bootstrapInfo, metricRecorder, transportCallCredentials, null);
1✔
97
  }
98

99
  @Override
100
  public ObjectPool<XdsClient> getOrCreate(
101
      String target, BootstrapInfo bootstrapInfo, MetricRecorder metricRecorder) {
102
    return getOrCreate(target, bootstrapInfo, metricRecorder, null, null);
1✔
103
  }
104

105
  @Override
106
  public ObjectPool<XdsClient> getOrCreate(
107
      String target, BootstrapInfo bootstrapInfo, MetricRecorder metricRecorder,
108
      ChannelConfigurator channelConfigurator) {
109
    return getOrCreate(target, bootstrapInfo, metricRecorder, null, channelConfigurator);
1✔
110
  }
111

112
  public ObjectPool<XdsClient> getOrCreate(
113
      String target,
114
      BootstrapInfo bootstrapInfo,
115
      MetricRecorder metricRecorder,
116
      CallCredentials transportCallCredentials,
117
      ChannelConfigurator channelConfigurator) {
118
    ObjectPool<XdsClient> ref = targetToXdsClientMap.get(target);
1✔
119
    if (ref == null) {
1✔
120
      synchronized (lock) {
1✔
121
        ref = targetToXdsClientMap.get(target);
1✔
122
        if (ref == null) {
1✔
123
          ref =
1✔
124
              new RefCountedXdsClientObjectPool(
125
                  bootstrapInfo, target, metricRecorder, transportCallCredentials,
126
                  channelConfigurator);
127
          targetToXdsClientMap.put(target, ref);
1✔
128
        }
129
      }
1✔
130
    }
131
    return ref;
1✔
132
  }
133

134
  @Override
135
  public ImmutableList<String> getTargets() {
136
    return ImmutableList.copyOf(targetToXdsClientMap.keySet());
1✔
137
  }
138

139
  private static class SharedXdsClientPoolProviderHolder {
140
    private static final SharedXdsClientPoolProvider instance = new SharedXdsClientPoolProvider();
1✔
141
  }
142

143
  @ThreadSafe
1✔
144
  @VisibleForTesting
145
  class RefCountedXdsClientObjectPool implements ObjectPool<XdsClient> {
146

147
    private final BootstrapInfo bootstrapInfo;
148
    private final String target; // The target associated with the xDS client.
149
    private final MetricRecorder metricRecorder;
150
    private final CallCredentials transportCallCredentials;
151
    private final ChannelConfigurator channelConfigurator;
152
    private final Object lock = new Object();
1✔
153
    @GuardedBy("lock")
154
    private ScheduledExecutorService scheduler;
155
    @GuardedBy("lock")
156
    private XdsClient xdsClient;
157
    @GuardedBy("lock")
158
    private int refCount;
159
    @GuardedBy("lock")
160
    private XdsClientMetricReporterImpl metricReporter;
161

162
    @VisibleForTesting
163
    RefCountedXdsClientObjectPool(
164
        BootstrapInfo bootstrapInfo, String target, MetricRecorder metricRecorder) {
165
      this(bootstrapInfo, target, metricRecorder, null, null);
1✔
166
    }
1✔
167

168
    @VisibleForTesting
169
    RefCountedXdsClientObjectPool(
170
        BootstrapInfo bootstrapInfo,
171
        String target,
172
        MetricRecorder metricRecorder,
173
        CallCredentials transportCallCredentials,
174
        ChannelConfigurator channelConfigurator) {
1✔
175
      this.bootstrapInfo = checkNotNull(bootstrapInfo, "bootstrapInfo");
1✔
176
      this.target = target;
1✔
177
      this.metricRecorder = checkNotNull(metricRecorder, "metricRecorder");
1✔
178
      this.transportCallCredentials = transportCallCredentials;
1✔
179
      this.channelConfigurator = channelConfigurator;
1✔
180
    }
1✔
181

182
    @Override
183
    public XdsClient getObject() {
184
      synchronized (lock) {
1✔
185
        if (refCount == 0) {
1✔
186
          if (LOG_XDS_NODE_ID) {
1✔
187
            log.log(Level.INFO, "xDS node ID: {0}", bootstrapInfo.node().getId());
×
188
          }
189
          scheduler = SharedResourceHolder.get(GrpcUtil.TIMER_SERVICE);
1✔
190
          metricReporter = new XdsClientMetricReporterImpl(metricRecorder, target);
1✔
191
          GrpcXdsTransportFactory xdsTransportFactory =
1✔
192
              new GrpcXdsTransportFactory(transportCallCredentials, channelConfigurator);
193
          xdsClient =
1✔
194
              new XdsClientImpl(
195
                  xdsTransportFactory,
196
                  bootstrapInfo,
197
                  scheduler,
198
                  BACKOFF_POLICY_PROVIDER,
1✔
199
                  GrpcUtil.STOPWATCH_SUPPLIER,
200
                  TimeProvider.SYSTEM_TIME_PROVIDER,
201
                  MessagePrinter.INSTANCE,
202
                  new TlsContextManagerImpl(bootstrapInfo),
203
                  metricReporter);
204
          metricReporter.setXdsClient(xdsClient);
1✔
205
        }
206
        refCount++;
1✔
207
        return xdsClient;
1✔
208
      }
209
    }
210

211
    @Override
212
    public XdsClient returnObject(Object object) {
213
      synchronized (lock) {
1✔
214
        refCount--;
1✔
215
        if (refCount == 0) {
1✔
216
          xdsClient.shutdown();
1✔
217
          xdsClient = null;
1✔
218
          metricReporter.close();
1✔
219
          metricReporter = null;
1✔
220
          targetToXdsClientMap.remove(target);
1✔
221
          scheduler = SharedResourceHolder.release(GrpcUtil.TIMER_SERVICE, scheduler);
1✔
222
        } else if (refCount < 0) {
1✔
223
          assert false; // We want our tests to fail
×
224
          log.log(Level.SEVERE, "Negative reference count. File a bug", new Exception());
×
225
          refCount = 0;
×
226
        }
227
        return null;
1✔
228
      }
229
    }
230

231
    @VisibleForTesting
232
    @Nullable
233
    XdsClient getXdsClientForTest() {
234
      synchronized (lock) {
1✔
235
        return xdsClient;
1✔
236
      }
237
    }
238

239
    public String getTarget() {
240
      return target;
×
241
    }
242
  }
243

244
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc