Skip to content

Commit 22cf7f9

Browse files
authored
Tolerate DefaultConnectionPool.ready/invalidate being called after or concurrently with close (#906)
JAVA-4551
1 parent a863ce6 commit 22cf7f9

File tree

2 files changed

+72
-5
lines changed

2 files changed

+72
-5
lines changed

driver-core/src/main/com/mongodb/internal/connection/DefaultConnectionPool.java

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
import java.util.concurrent.Executors;
7070
import java.util.concurrent.Future;
7171
import java.util.concurrent.LinkedBlockingQueue;
72+
import java.util.concurrent.RejectedExecutionException;
7273
import java.util.concurrent.ScheduledExecutorService;
7374
import java.util.concurrent.TimeUnit;
7475
import java.util.concurrent.atomic.AtomicBoolean;
@@ -1416,18 +1417,21 @@ private BackgroundMaintenanceManager() {
14161417
void start() {
14171418
if (maintainer != null) {
14181419
assertTrue(cancellationHandle == null);
1419-
cancellationHandle = maintainer.scheduleAtFixedRate(DefaultConnectionPool.this::doMaintenance,
1420+
cancellationHandle = ignoreRejectedExectution(() -> maintainer.scheduleAtFixedRate(
1421+
DefaultConnectionPool.this::doMaintenance,
14201422
initialStart ? settings.getMaintenanceInitialDelay(MILLISECONDS) : 0,
1421-
settings.getMaintenanceFrequency(MILLISECONDS), MILLISECONDS);
1423+
settings.getMaintenanceFrequency(MILLISECONDS), MILLISECONDS));
14221424
initialStart = false;
14231425
}
14241426
}
14251427

14261428
void runOnceAndStop() {
14271429
if (maintainer != null) {
1428-
assertNotNull(cancellationHandle).cancel(false);
1429-
cancellationHandle = null;
1430-
maintainer.execute(DefaultConnectionPool.this::doMaintenance);
1430+
if (cancellationHandle != null) {
1431+
cancellationHandle.cancel(false);
1432+
cancellationHandle = null;
1433+
}
1434+
ignoreRejectedExectution(() -> maintainer.execute(DefaultConnectionPool.this::doMaintenance));
14311435
}
14321436
}
14331437

@@ -1437,6 +1441,23 @@ public void close() {
14371441
maintainer.shutdownNow();
14381442
}
14391443
}
1444+
1445+
private void ignoreRejectedExectution(final Runnable action) {
1446+
ignoreRejectedExectution(() -> {
1447+
action.run();
1448+
return null;
1449+
});
1450+
}
1451+
1452+
@Nullable
1453+
private <T> T ignoreRejectedExectution(final Supplier<T> action) {
1454+
try {
1455+
return action.get();
1456+
} catch (RejectedExecutionException ignored) {
1457+
// `close` either completed or is in progress
1458+
return null;
1459+
}
1460+
}
14401461
}
14411462

14421463
@ThreadSafe

driver-core/src/test/functional/com/mongodb/internal/connection/DefaultConnectionPoolTest.java

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,52 @@ public void checkoutHandOverMechanism() throws InterruptedException, TimeoutExce
443443
}
444444
}
445445

446+
@Test
447+
public void readyAfterCloseMustNotThrow() {
448+
provider = new DefaultConnectionPool(
449+
SERVER_ID,
450+
connectionFactory,
451+
ConnectionPoolSettings.builder().maxSize(1).build(),
452+
mockSdamProvider());
453+
provider.close();
454+
provider.ready();
455+
}
456+
457+
@Test
458+
public void invalidateAfterCloseMustNotThrow() {
459+
provider = new DefaultConnectionPool(
460+
SERVER_ID,
461+
connectionFactory,
462+
ConnectionPoolSettings.builder().maxSize(1).build(),
463+
mockSdamProvider());
464+
provider.ready();
465+
provider.close();
466+
provider.invalidate(null);
467+
}
468+
469+
@Test
470+
public void readyInvalidateConcurrentWithCloseMustNotThrow() throws ExecutionException, InterruptedException {
471+
Future<?> readyAndInvalidateResult = null;
472+
for (int i = 0; i < 3_000; i++) {
473+
provider = new DefaultConnectionPool(
474+
SERVER_ID,
475+
connectionFactory,
476+
ConnectionPoolSettings.builder().maxSize(1).build(),
477+
mockSdamProvider());
478+
try {
479+
readyAndInvalidateResult = cachedExecutor.submit(() -> {
480+
provider.ready();
481+
provider.invalidate(null);
482+
});
483+
} finally {
484+
provider.close();
485+
if (readyAndInvalidateResult != null) {
486+
readyAndInvalidateResult.get();
487+
}
488+
}
489+
}
490+
}
491+
446492
private static void assertUseConcurrently(final DefaultConnectionPool pool, final int concurrentUsersCount,
447493
final boolean sync, final boolean async,
448494
final float invalidateAndReadyProb, final float invalidateProb, final float readyProb,

0 commit comments

Comments
 (0)