Skip to content

Commit 6ed5c98

Browse files
committed
Fix borrow accounting on keyspace setup failure
1 parent 1239ffd commit 6ed5c98

3 files changed

Lines changed: 67 additions & 2 deletions

File tree

driver-core/src/main/java/com/datastax/driver/core/Connection.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -900,7 +900,14 @@ ListenableFuture<Connection> setKeyspaceAsync(final String keyspace)
900900
logger.debug("{} Setting keyspace {}", this, keyspace);
901901
// Note: we quote the keyspace below, because the name is the one coming from Cassandra, so
902902
// it's in the right case already
903-
Future future = write(new Requests.Query("USE \"" + keyspace + '"'));
903+
Future future;
904+
try {
905+
future = write(new Requests.Query("USE \"" + keyspace + '"'));
906+
} catch (RuntimeException e) {
907+
targetKeyspace.compareAndSet(attempt, existingAttempt);
908+
ksFuture.setException(e);
909+
throw e;
910+
}
904911
Futures.addCallback(
905912
future,
906913
new FutureCallback<Message.Response>() {

driver-core/src/main/java/com/datastax/driver/core/HostConnectionPool.java

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import static com.datastax.driver.core.Connection.State.TRASHED;
2828

2929
import com.datastax.driver.core.exceptions.AuthenticationException;
30+
import com.datastax.driver.core.exceptions.BusyConnectionException;
3031
import com.datastax.driver.core.exceptions.BusyPoolException;
3132
import com.datastax.driver.core.exceptions.ConnectionException;
3233
import com.datastax.driver.core.exceptions.UnsupportedProtocolVersionException;
@@ -611,7 +612,30 @@ ListenableFuture<Connection> borrowConnection(
611612
if (totalInFlightCount > currentCapacity) maybeSpawnNewConnection(shardId);
612613
}
613614

614-
return leastBusy.setKeyspaceAsync(manager.poolsState.keyspace);
615+
final Connection borrowedConnection = leastBusy;
616+
ListenableFuture<Connection> setKeyspaceFuture;
617+
try {
618+
setKeyspaceFuture = borrowedConnection.setKeyspaceAsync(manager.poolsState.keyspace);
619+
} catch (BusyConnectionException e) {
620+
borrowedConnection.release(true);
621+
throw e;
622+
} catch (RuntimeException e) {
623+
borrowedConnection.release(false);
624+
throw e;
625+
}
626+
Futures.addCallback(
627+
setKeyspaceFuture,
628+
new FutureCallback<Connection>() {
629+
@Override
630+
public void onSuccess(Connection connection) {}
631+
632+
@Override
633+
public void onFailure(Throwable t) {
634+
borrowedConnection.release(false);
635+
}
636+
},
637+
MoreExecutors.directExecutor());
638+
return setKeyspaceFuture;
615639
}
616640

617641
private ListenableFuture<Connection> enqueue(

driver-core/src/test/java/com/datastax/driver/core/HostConnectionPoolTest.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
import com.google.common.util.concurrent.ListeningExecutorService;
6363
import com.google.common.util.concurrent.MoreExecutors;
6464
import com.google.common.util.concurrent.Uninterruptibles;
65+
import java.lang.reflect.Field;
6566
import java.net.InetSocketAddress;
6667
import java.nio.ByteBuffer;
6768
import java.util.Collection;
@@ -434,6 +435,33 @@ public void should_adjust_connection_keyspace_on_dequeue_if_pool_state_is_differ
434435
.contains(
435436
"Aborting attempt to set keyspace to 'newks' since there is already an in flight attempt to set keyspace to 'slowks'.");
436437
}
438+
assertThat(connection.inFlight.get()).isEqualTo(0);
439+
assertThat(pool.totalInFlight.get()).isEqualTo(0);
440+
} finally {
441+
cluster.close();
442+
}
443+
}
444+
445+
@Test(groups = "short")
446+
public void should_restore_borrow_counts_when_set_keyspace_throws_synchronously()
447+
throws Exception {
448+
Cluster cluster = createClusterBuilder().build();
449+
try {
450+
HostConnectionPool pool = createPool(cluster, 1, 1);
451+
Connection connection = pool.connections[0].get(0);
452+
453+
pool.manager.poolsState.setKeyspace("newkeyspace");
454+
markDefunctWithoutClosing(connection);
455+
456+
try {
457+
pool.borrowConnection(5000, MILLISECONDS, 0, null, null, null, null);
458+
fail("Expected a ConnectionException");
459+
} catch (ConnectionException e) {
460+
assertThat(e.getMessage()).contains("Write attempt on defunct connection");
461+
}
462+
463+
assertThat(connection.inFlight.get()).isEqualTo(0);
464+
assertThat(pool.totalInFlight.get()).isEqualTo(0);
437465
} finally {
438466
cluster.close();
439467
}
@@ -1412,6 +1440,12 @@ private HostConnectionPool createPool(Cluster cluster, int coreConnections, int
14121440
return sm.pools.get(host);
14131441
}
14141442

1443+
private void markDefunctWithoutClosing(Connection connection) throws Exception {
1444+
Field isDefunct = Connection.class.getDeclaredField("isDefunct");
1445+
isDefunct.setAccessible(true);
1446+
((AtomicBoolean) isDefunct.get(connection)).set(true);
1447+
}
1448+
14151449
/**
14161450
* This test uses a table named "Java349" with 1000 column and performs asynchronously 100k
14171451
* insertions. While the insertions are being executed, the number of opened connection is

0 commit comments

Comments
 (0)