3838import java .nio .ByteBuffer ;
3939import java .util .ArrayList ;
4040import java .util .Collection ;
41+ import java .util .HashMap ;
4142import java .util .List ;
43+ import java .util .Map ;
4244import java .util .Queue ;
4345import java .util .Random ;
4446import java .util .Set ;
@@ -97,7 +99,60 @@ private enum Phase {
9799
98100 protected final AtomicReference <Phase > phase = new AtomicReference <Phase >(Phase .INITIALIZING );
99101
102+ public static class ConnectionTasksSharedState {
103+ private final Object lock = new Object ();
104+ private int tasksInFlight = 0 ;
105+ private Map <Integer , Connection > connectionsToClose = new HashMap <Integer , Connection >();
106+
107+ public Connection registerTask (int shardId ) {
108+ Connection c = null ;
109+ synchronized (lock ) {
110+ c = connectionsToClose .remove (shardId );
111+ if (c == null ) {
112+ ++tasksInFlight ;
113+ }
114+ }
115+ return c ;
116+ }
117+
118+ public void unregisterTask () {
119+ Map <Integer , Connection > toClose = null ;
120+ synchronized (lock ) {
121+ --tasksInFlight ;
122+ if (tasksInFlight == 0 ) {
123+ toClose = connectionsToClose ;
124+ connectionsToClose = new HashMap <Integer , Connection >();
125+ }
126+ }
127+ if (toClose != null ) {
128+ for (Connection c : toClose .values ()) {
129+ c .closeAsync ();
130+ }
131+ }
132+ }
133+
134+ public Connection addConnectionToClose (int shardId , Connection c ) {
135+ Connection res = null ;
136+ boolean close = false ;
137+ synchronized (lock ) {
138+ res = connectionsToClose .remove (shardId );
139+ close = connectionsToClose .get (c .shardId ()) != null ;
140+ if (!close ) {
141+ connectionsToClose .put (c .shardId (), c );
142+ }
143+ }
144+ if (close ) {
145+ c .closeAsync ();
146+ }
147+ return res ;
148+ }
149+ }
150+
151+ private final ConnectionTasksSharedState connectionTasksSharedState =
152+ new ConnectionTasksSharedState ();
153+
100154 private class ConnectionTask implements Runnable {
155+
101156 private final int shardId ;
102157
103158 public ConnectionTask (int shardId ) {
@@ -106,7 +161,7 @@ public ConnectionTask(int shardId) {
106161
107162 @ Override
108163 public void run () {
109- addConnectionIfUnderMaximum (shardId );
164+ addConnectionIfUnderMaximum (shardId , connectionTasksSharedState );
110165 scheduledForCreation [shardId ].decrementAndGet ();
111166 }
112167 }
@@ -585,7 +640,7 @@ private void doTrashConnection(Connection connection) {
585640 trash [connection .shardId ()].add (connection );
586641 }
587642
588- private boolean addConnectionIfUnderMaximum (int shardId ) {
643+ private boolean addConnectionIfUnderMaximum (int shardId , ConnectionTasksSharedState sharedState ) {
589644
590645 // First, make sure we don't cross the allowed limit of open connections
591646 for (; ; ) {
@@ -609,23 +664,19 @@ private boolean addConnectionIfUnderMaximum(int shardId) {
609664 return false ;
610665 }
611666 logger .debug ("Creating new connection on busy pool to {}" , host );
612- List <Connection > toClose = new ArrayList <Connection >();
613- try {
614- while (true ) {
615- newConnection = manager .connectionFactory ().open (this );
616- if (newConnection .shardId () == shardId ) {
617- newConnection .setKeyspace (manager .poolsState .keyspace );
618- break ;
619- }
620- if (toClose .size () < connections .length ) {
621- toClose .add (newConnection );
622- } else {
623- newConnection .closeAsync ();
624- }
625- }
626- } finally {
627- for (Connection c : toClose ) {
628- c .closeAsync ();
667+ newConnection = sharedState .registerTask (shardId );
668+ if (newConnection == null ) {
669+ try {
670+ do {
671+ newConnection = manager .connectionFactory ().open (this );
672+ if (newConnection .shardId () == shardId ) {
673+ newConnection .setKeyspace (manager .poolsState .keyspace );
674+ } else {
675+ newConnection = sharedState .addConnectionToClose (shardId , newConnection );
676+ }
677+ } while (newConnection == null );
678+ } finally {
679+ sharedState .unregisterTask ();
629680 }
630681 }
631682 }
0 commit comments