1717package com .google .cloud .pubsublite .internal ;
1818
1919import com .google .common .annotations .VisibleForTesting ;
20+ import com .google .common .flogger .GoogleLogger ;
2021import io .grpc .Channel ;
2122import io .grpc .ManagedChannel ;
2223import io .grpc .ManagedChannelBuilder ;
24+ import java .util .Deque ;
25+ import java .util .LinkedList ;
2326import java .util .concurrent .ConcurrentHashMap ;
2427import java .util .concurrent .TimeUnit ;
2528import java .util .function .Function ;
2629
2730/** A ChannelCache creates and stores default channels for use with api methods. */
2831public class ChannelCache {
32+ private static final GoogleLogger log = GoogleLogger .forEnclosingClass ();
33+
2934 private final Function <String , ManagedChannel > channelFactory ;
30- private final ConcurrentHashMap <String , ManagedChannel > channels = new ConcurrentHashMap <>();
35+ private final ConcurrentHashMap <String , Deque <ManagedChannel >> channels =
36+ new ConcurrentHashMap <>();
37+
38+ private static final int NUMBER_OF_CHANNELS_PER_TARGET = 10 ;
39+ private static final String NUMBER_OF_CHANNELS_PER_TARGET_VM_OVERRIDE =
40+ "google.cloud.pubsublite.channelCacheSize" ;
3141
3242 public ChannelCache () {
3343 this (ChannelCache ::newChannel );
@@ -40,20 +50,45 @@ public ChannelCache() {
4050 }
4151
4252 @ VisibleForTesting
43- void onShutdown () {
53+ synchronized void onShutdown () {
4454 channels .forEachValue (
4555 channels .size (),
46- channel -> {
56+ channels -> {
4757 try {
48- channel .shutdownNow ().awaitTermination (60 , TimeUnit .SECONDS );
58+ for (ManagedChannel channel : channels ) {
59+ channel .shutdownNow ().awaitTermination (60 , TimeUnit .SECONDS );
60+ }
4961 } catch (InterruptedException e ) {
5062 e .printStackTrace ();
5163 }
5264 });
5365 }
5466
55- public Channel get (String target ) {
56- return channels .computeIfAbsent (target , channelFactory );
67+ public synchronized Channel get (String target ) {
68+ Deque <ManagedChannel > channelQueue = channels .computeIfAbsent (target , this ::newChannels );
69+ ManagedChannel channel = channelQueue .removeFirst ();
70+ channelQueue .addLast (channel );
71+ return channel ;
72+ }
73+
74+ private Deque <ManagedChannel > newChannels (String target ) {
75+ int numberOfChannels = NUMBER_OF_CHANNELS_PER_TARGET ;
76+ String numberOfChannelsOverride = System .getProperty (NUMBER_OF_CHANNELS_PER_TARGET_VM_OVERRIDE );
77+ if (numberOfChannelsOverride != null && !numberOfChannelsOverride .isEmpty ()) {
78+ try {
79+ numberOfChannels = Integer .parseInt ((numberOfChannelsOverride ));
80+ } catch (NumberFormatException e ) {
81+ log .atSevere ().log (
82+ "Unable to parse override for number of channels per target: %s" ,
83+ numberOfChannelsOverride );
84+ }
85+ }
86+
87+ Deque <ManagedChannel > channels = new LinkedList <>();
88+ for (int i = 0 ; i < numberOfChannels ; i ++) {
89+ channels .add (channelFactory .apply (target ));
90+ }
91+ return channels ;
5792 }
5893
5994 private static ManagedChannel newChannel (String target ) {
0 commit comments