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

grpc / grpc-java / #19437

23 Aug 2024 08:05PM UTC coverage: 84.514% (+0.01%) from 84.503%
#19437

push

github

web-flow
Xds client split (#11484)

33415 of 39538 relevant lines covered (84.51%)

0.85 hits per line

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

96.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
import static io.grpc.xds.GrpcXdsTransportFactory.DEFAULT_XDS_TRANSPORT_FACTORY;
21

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

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

55
  private final Bootstrapper bootstrapper;
56
  private final Object lock = new Object();
1✔
57
  private final AtomicReference<Map<String, ?>> bootstrapOverride = new AtomicReference<>();
1✔
58
  private final Map<String, ObjectPool<XdsClient>> targetToXdsClientMap = new ConcurrentHashMap<>();
1✔
59

60
  SharedXdsClientPoolProvider() {
61
    this(new GrpcBootstrapperImpl());
1✔
62
  }
1✔
63

64
  @VisibleForTesting
65
  SharedXdsClientPoolProvider(Bootstrapper bootstrapper) {
1✔
66
    this.bootstrapper = checkNotNull(bootstrapper, "bootstrapper");
1✔
67
  }
1✔
68

69
  static SharedXdsClientPoolProvider getDefaultProvider() {
70
    return SharedXdsClientPoolProviderHolder.instance;
1✔
71
  }
72

73
  @Override
74
  public void setBootstrapOverride(Map<String, ?> bootstrap) {
75
    bootstrapOverride.set(bootstrap);
1✔
76
  }
1✔
77

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

84
  @Override
85
  public ObjectPool<XdsClient> getOrCreate(String target) throws XdsInitializationException {
86
    ObjectPool<XdsClient> ref = targetToXdsClientMap.get(target);
1✔
87
    if (ref == null) {
1✔
88
      synchronized (lock) {
1✔
89
        ref = targetToXdsClientMap.get(target);
1✔
90
        if (ref == null) {
1✔
91
          BootstrapInfo bootstrapInfo;
92
          Map<String, ?> rawBootstrap = bootstrapOverride.get();
1✔
93
          if (rawBootstrap != null) {
1✔
94
            bootstrapInfo = bootstrapper.bootstrap(rawBootstrap);
1✔
95
          } else {
96
            bootstrapInfo = bootstrapper.bootstrap();
1✔
97
          }
98
          if (bootstrapInfo.servers().isEmpty()) {
1✔
99
            throw new XdsInitializationException("No xDS server provided");
1✔
100
          }
101
          ref = new RefCountedXdsClientObjectPool(bootstrapInfo, target);
1✔
102
          targetToXdsClientMap.put(target, ref);
1✔
103
        }
104
      }
1✔
105
    }
106
    return ref;
1✔
107
  }
108

109
  @Override
110
  public ImmutableList<String> getTargets() {
111
    return ImmutableList.copyOf(targetToXdsClientMap.keySet());
1✔
112
  }
113

114

115
  private static class SharedXdsClientPoolProviderHolder {
116
    private static final SharedXdsClientPoolProvider instance = new SharedXdsClientPoolProvider();
1✔
117
  }
118

119
  @ThreadSafe
120
  @VisibleForTesting
121
  static class RefCountedXdsClientObjectPool implements ObjectPool<XdsClient> {
122

123
    private static final ExponentialBackoffPolicy.Provider BACKOFF_POLICY_PROVIDER =
1✔
124
        new ExponentialBackoffPolicy.Provider();
125
    private final BootstrapInfo bootstrapInfo;
126
    private final String target; // The target associated with the xDS client.
127
    private final Object lock = new Object();
1✔
128
    @GuardedBy("lock")
129
    private ScheduledExecutorService scheduler;
130
    @GuardedBy("lock")
131
    private XdsClient xdsClient;
132
    @GuardedBy("lock")
133
    private int refCount;
134

135
    @VisibleForTesting
136
    RefCountedXdsClientObjectPool(BootstrapInfo bootstrapInfo, String target) {
1✔
137
      this.bootstrapInfo = checkNotNull(bootstrapInfo);
1✔
138
      this.target = target;
1✔
139
    }
1✔
140

141
    @Override
142
    public XdsClient getObject() {
143
      synchronized (lock) {
1✔
144
        if (refCount == 0) {
1✔
145
          if (LOG_XDS_NODE_ID) {
1✔
146
            log.log(Level.INFO, "xDS node ID: {0}", bootstrapInfo.node().getId());
×
147
          }
148
          scheduler = SharedResourceHolder.get(GrpcUtil.TIMER_SERVICE);
1✔
149
          xdsClient = new XdsClientImpl(
1✔
150
              DEFAULT_XDS_TRANSPORT_FACTORY,
151
              bootstrapInfo,
152
              scheduler,
153
              BACKOFF_POLICY_PROVIDER,
154
              GrpcUtil.STOPWATCH_SUPPLIER,
155
              TimeProvider.SYSTEM_TIME_PROVIDER,
156
              MessagePrinter.INSTANCE,
157
              new TlsContextManagerImpl(bootstrapInfo));
158
        }
159
        refCount++;
1✔
160
        return xdsClient;
1✔
161
      }
162
    }
163

164
    @Override
165
    public XdsClient returnObject(Object object) {
166
      synchronized (lock) {
1✔
167
        refCount--;
1✔
168
        if (refCount == 0) {
1✔
169
          xdsClient.shutdown();
1✔
170
          xdsClient = null;
1✔
171
          scheduler = SharedResourceHolder.release(GrpcUtil.TIMER_SERVICE, scheduler);
1✔
172
        }
173
        return null;
1✔
174
      }
175
    }
176

177
    @VisibleForTesting
178
    @Nullable
179
    XdsClient getXdsClientForTest() {
180
      synchronized (lock) {
1✔
181
        return xdsClient;
1✔
182
      }
183
    }
184

185
    public String getTarget() {
186
      return target;
×
187
    }
188
  }
189

190
}
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

© 2025 Coveralls, Inc