2929import java .util .Map ;
3030import java .util .concurrent .ConcurrentHashMap ;
3131import java .util .concurrent .TimeUnit ;
32+ import java .util .concurrent .atomic .AtomicBoolean ;
3233
3334/**
34- * gRPC implementation of {@link ChannelFinderServerFactory }.
35+ * gRPC implementation of {@link ChannelEndpointCache }.
3536 *
36- * <p>This factory creates and caches gRPC channels per address. It uses {@link
37+ * <p>This cache creates and caches gRPC channels per address. It uses {@link
3738 * InstantiatingGrpcChannelProvider#withEndpoint(String)} to create new channels with the same
3839 * configuration but different endpoints, avoiding race conditions.
3940 */
4041@ InternalApi
41- class GrpcChannelFinderServerFactory implements ChannelFinderServerFactory {
42+ class GrpcChannelEndpointCache implements ChannelEndpointCache {
4243
4344 /** Timeout for graceful channel shutdown. */
4445 private static final long SHUTDOWN_TIMEOUT_SECONDS = 5 ;
4546
4647 private final InstantiatingGrpcChannelProvider baseProvider ;
47- private final Map <String , GrpcChannelFinderServer > servers = new ConcurrentHashMap <>();
48- private final GrpcChannelFinderServer defaultServer ;
49- private volatile boolean isShutdown = false ;
48+ private final Map <String , GrpcChannelEndpoint > servers = new ConcurrentHashMap <>();
49+ private final GrpcChannelEndpoint defaultEndpoint ;
50+ private final AtomicBoolean isShutdown = new AtomicBoolean ( false ) ;
5051
5152 /**
52- * Creates a new factory with the given channel provider.
53+ * Creates a new cache with the given channel provider.
5354 *
5455 * @param channelProvider the base provider used to create channels. New channels for different
5556 * endpoints are created using {@link InstantiatingGrpcChannelProvider#withEndpoint(String)}.
5657 * @throws IOException if the default channel cannot be created
5758 */
58- public GrpcChannelFinderServerFactory (InstantiatingGrpcChannelProvider channelProvider )
59+ public GrpcChannelEndpointCache (InstantiatingGrpcChannelProvider channelProvider )
5960 throws IOException {
6061 this .baseProvider = channelProvider ;
6162 String defaultEndpoint = channelProvider .getEndpoint ();
62- this .defaultServer = new GrpcChannelFinderServer (defaultEndpoint , channelProvider );
63- this .servers .put (defaultEndpoint , this .defaultServer );
63+ this .defaultEndpoint = new GrpcChannelEndpoint (defaultEndpoint , channelProvider );
64+ this .servers .put (defaultEndpoint , this .defaultEndpoint );
6465 }
6566
6667 @ Override
67- public ChannelFinderServer defaultServer () {
68- return defaultServer ;
68+ public ChannelEndpoint defaultChannel () {
69+ return defaultEndpoint ;
6970 }
7071
7172 @ Override
72- public ChannelFinderServer create (String address ) {
73- if (isShutdown ) {
73+ public ChannelEndpoint get (String address ) {
74+ if (isShutdown . get () ) {
7475 throw SpannerExceptionFactory .newSpannerException (
75- ErrorCode .FAILED_PRECONDITION , "ChannelFinderServerFactory has been shut down" );
76+ ErrorCode .FAILED_PRECONDITION , "ChannelEndpointCache has been shut down" );
7677 }
7778
7879 return servers .computeIfAbsent (
@@ -82,7 +83,7 @@ public ChannelFinderServer create(String address) {
8283 // Create a new provider with the same config but different endpoint.
8384 // This is thread-safe as withEndpoint() returns a new provider instance.
8485 TransportChannelProvider newProvider = baseProvider .withEndpoint (addr );
85- return new GrpcChannelFinderServer (addr , newProvider );
86+ return new GrpcChannelEndpoint (addr , newProvider );
8687 } catch (IOException e ) {
8788 throw SpannerExceptionFactory .newSpannerException (
8889 ErrorCode .INTERNAL , "Failed to create channel for address: " + addr , e );
@@ -92,37 +93,42 @@ public ChannelFinderServer create(String address) {
9293
9394 @ Override
9495 public void evict (String address ) {
95- if (defaultServer .getAddress ().equals (address )) {
96+ if (defaultEndpoint .getAddress ().equals (address )) {
9697 return ;
9798 }
98- GrpcChannelFinderServer server = servers .remove (address );
99+ GrpcChannelEndpoint server = servers .remove (address );
99100 if (server != null ) {
100- shutdownServerGracefully (server );
101+ shutdownChannel (server , false );
101102 }
102103 }
103104
104105 @ Override
105106 public void shutdown () {
106- isShutdown = true ;
107- for (GrpcChannelFinderServer server : servers .values ()) {
108- shutdownServerGracefully (server );
107+ if (!isShutdown .compareAndSet (false , true )) {
108+ return ;
109+ }
110+ for (GrpcChannelEndpoint server : servers .values ()) {
111+ shutdownChannel (server , true );
109112 }
110113 servers .clear ();
111114 }
112115
113116 /**
114- * Gracefully shuts down a server's channel.
117+ * Shuts down a server's channel.
115118 *
116- * <p>First attempts a graceful shutdown, waiting for in-flight RPCs to complete. If the timeout
117- * is exceeded, forces immediate shutdown.
119+ * <p>First attempts a graceful shutdown. When awaitTermination is true, waits for in-flight RPCs
120+ * to complete and forces shutdown on timeout .
118121 */
119- private void shutdownServerGracefully ( GrpcChannelFinderServer server ) {
122+ private void shutdownChannel ( GrpcChannelEndpoint server , boolean awaitTermination ) {
120123 ManagedChannel channel = server .getChannel ();
121124 if (channel .isShutdown ()) {
122125 return ;
123126 }
124127
125128 channel .shutdown ();
129+ if (!awaitTermination ) {
130+ return ;
131+ }
126132 try {
127133 if (!channel .awaitTermination (SHUTDOWN_TIMEOUT_SECONDS , TimeUnit .SECONDS )) {
128134 channel .shutdownNow ();
@@ -133,8 +139,8 @@ private void shutdownServerGracefully(GrpcChannelFinderServer server) {
133139 }
134140 }
135141
136- /** gRPC implementation of {@link ChannelFinderServer }. */
137- static class GrpcChannelFinderServer implements ChannelFinderServer {
142+ /** gRPC implementation of {@link ChannelEndpoint }. */
143+ static class GrpcChannelEndpoint implements ChannelEndpoint {
138144 private final String address ;
139145 private final ManagedChannel channel ;
140146
@@ -145,7 +151,7 @@ static class GrpcChannelFinderServer implements ChannelFinderServer {
145151 * @param provider the channel provider (must be a gRPC provider)
146152 * @throws IOException if the channel cannot be created
147153 */
148- GrpcChannelFinderServer (String address , TransportChannelProvider provider ) throws IOException {
154+ GrpcChannelEndpoint (String address , TransportChannelProvider provider ) throws IOException {
149155 this .address = address ;
150156 TransportChannelProvider readyProvider = provider ;
151157 if (provider .needsHeaders ()) {
@@ -163,7 +169,7 @@ static class GrpcChannelFinderServer implements ChannelFinderServer {
163169 * @param channel the managed channel
164170 */
165171 @ VisibleForTesting
166- GrpcChannelFinderServer (String address , ManagedChannel channel ) {
172+ GrpcChannelEndpoint (String address , ManagedChannel channel ) {
167173 this .address = address ;
168174 this .channel = channel ;
169175 }
@@ -184,7 +190,7 @@ public boolean isHealthy() {
184190 try {
185191 ConnectivityState state = channel .getState (false );
186192 return state != ConnectivityState .SHUTDOWN && state != ConnectivityState .TRANSIENT_FAILURE ;
187- } catch (UnsupportedOperationException e ) {
193+ } catch (UnsupportedOperationException ignore ) {
188194 return true ;
189195 }
190196 }
0 commit comments