use of com.google.cloud.spanner.SessionPool.PooledSessionFuture in project java-spanner by googleapis.
the class SessionPoolTest method poolClosureFailsPendingWriteWaiters.
@Test
public void poolClosureFailsPendingWriteWaiters() throws Exception {
final CountDownLatch insideCreation = new CountDownLatch(1);
final CountDownLatch releaseCreation = new CountDownLatch(1);
final SessionImpl session1 = mockSession();
final SessionImpl session2 = mockSession();
doAnswer(invocation -> {
executor.submit(() -> {
SessionConsumerImpl consumer = invocation.getArgument(2, SessionConsumerImpl.class);
consumer.onSessionReady(session1);
});
return null;
}).doAnswer(invocation -> {
executor.submit(() -> {
insideCreation.countDown();
releaseCreation.await();
SessionConsumerImpl consumer = invocation.getArgument(2, SessionConsumerImpl.class);
consumer.onSessionReady(session2);
return null;
});
return null;
}).when(sessionClient).asyncBatchCreateSessions(Mockito.eq(1), Mockito.anyBoolean(), any(SessionConsumer.class));
pool = createPool();
PooledSessionFuture leakedSession = pool.getSession();
// Suppress expected leakedSession warning.
leakedSession.clearLeakedException();
AtomicBoolean failed = new AtomicBoolean(false);
CountDownLatch latch = new CountDownLatch(1);
getSessionAsync(latch, failed);
insideCreation.await();
pool.closeAsync(new SpannerImpl.ClosedException());
releaseCreation.countDown();
latch.await();
assertThat(failed.get()).isTrue();
}
use of com.google.cloud.spanner.SessionPool.PooledSessionFuture in project java-spanner by googleapis.
the class SessionPoolTest method blockAndTimeoutOnPoolExhaustion.
@Test
public void blockAndTimeoutOnPoolExhaustion() throws Exception {
// Create a session pool with max 1 session and a low timeout for waiting for a session.
options = SessionPoolOptions.newBuilder().setMinSessions(minSessions).setMaxSessions(1).setInitialWaitForSessionTimeoutMillis(20L).build();
setupMockSessionCreation();
pool = createPool();
// Take the only session that can be in the pool.
PooledSessionFuture checkedOutSession = pool.getSession();
checkedOutSession.get();
ExecutorService executor = Executors.newFixedThreadPool(1);
final CountDownLatch latch = new CountDownLatch(1);
// Then try asynchronously to take another session. This attempt should time out.
Future<Void> fut = executor.submit(() -> {
latch.countDown();
PooledSessionFuture session = pool.getSession();
session.close();
return null;
});
// Wait until the background thread is actually waiting for a session.
latch.await();
// Wait until the request has timed out.
int waitCount = 0;
while (pool.getNumWaiterTimeouts() == 0L && waitCount < 1000) {
Thread.sleep(5L);
waitCount++;
}
// Return the checked out session to the pool so the async request will get a session and
// finish.
checkedOutSession.close();
// Verify that the async request also succeeds.
fut.get(10L, TimeUnit.SECONDS);
executor.shutdown();
// Verify that the session was returned to the pool and that we can get it again.
Session session = pool.getSession();
assertThat(session).isNotNull();
session.close();
assertThat(pool.getNumWaiterTimeouts()).isAtLeast(1L);
}
use of com.google.cloud.spanner.SessionPool.PooledSessionFuture in project java-spanner by googleapis.
the class SessionPoolTest method poolClosureFailsPendingReadWaiters.
@Test
public void poolClosureFailsPendingReadWaiters() throws Exception {
final CountDownLatch insideCreation = new CountDownLatch(1);
final CountDownLatch releaseCreation = new CountDownLatch(1);
final SessionImpl session1 = mockSession();
final SessionImpl session2 = mockSession();
doAnswer(invocation -> {
executor.submit(() -> {
SessionConsumerImpl consumer = invocation.getArgument(2, SessionConsumerImpl.class);
consumer.onSessionReady(session1);
});
return null;
}).doAnswer(invocation -> {
executor.submit(() -> {
insideCreation.countDown();
releaseCreation.await();
SessionConsumerImpl consumer = invocation.getArgument(2, SessionConsumerImpl.class);
consumer.onSessionReady(session2);
return null;
});
return null;
}).when(sessionClient).asyncBatchCreateSessions(Mockito.eq(1), Mockito.anyBoolean(), any(SessionConsumer.class));
pool = createPool();
PooledSessionFuture leakedSession = pool.getSession();
// Suppress expected leakedSession warning.
leakedSession.clearLeakedException();
AtomicBoolean failed = new AtomicBoolean(false);
CountDownLatch latch = new CountDownLatch(1);
getSessionAsync(latch, failed);
insideCreation.await();
pool.closeAsync(new SpannerImpl.ClosedException());
releaseCreation.countDown();
latch.await(5L, TimeUnit.SECONDS);
assertThat(failed.get()).isTrue();
}
use of com.google.cloud.spanner.SessionPool.PooledSessionFuture in project java-spanner by googleapis.
the class SessionPoolTest method idleSessionCleanup.
@Test
public void idleSessionCleanup() throws Exception {
options = SessionPoolOptions.newBuilder().setMinSessions(1).setMaxSessions(3).setIncStep(1).setMaxIdleSessions(0).build();
SessionImpl session1 = mockSession();
SessionImpl session2 = mockSession();
SessionImpl session3 = mockSession();
final LinkedList<SessionImpl> sessions = new LinkedList<>(Arrays.asList(session1, session2, session3));
doAnswer(invocation -> {
executor.submit(() -> {
SessionConsumerImpl consumer = invocation.getArgument(2, SessionConsumerImpl.class);
consumer.onSessionReady(sessions.pop());
});
return null;
}).when(sessionClient).asyncBatchCreateSessions(Mockito.eq(1), Mockito.anyBoolean(), any(SessionConsumer.class));
for (SessionImpl session : sessions) {
mockKeepAlive(session);
}
FakeClock clock = new FakeClock();
clock.currentTimeMillis = System.currentTimeMillis();
pool = createPool(clock);
// Make sure pool has been initialized
pool.getSession().close();
runMaintenanceLoop(clock, pool, pool.poolMaintainer.numClosureCycles);
assertThat(pool.numIdleSessionsRemoved()).isEqualTo(0L);
PooledSessionFuture readSession1 = pool.getSession();
PooledSessionFuture readSession2 = pool.getSession();
PooledSessionFuture readSession3 = pool.getSession();
// Wait until the sessions have actually been gotten in order to make sure they are in use in
// parallel.
readSession1.get();
readSession2.get();
readSession3.get();
readSession1.close();
readSession2.close();
readSession3.close();
// Now there are 3 sessions in the pool but since none of them has timed out, they will all be
// kept in the pool.
runMaintenanceLoop(clock, pool, pool.poolMaintainer.numClosureCycles);
assertThat(pool.numIdleSessionsRemoved()).isEqualTo(0L);
// Counters have now been reset
// Use all 3 sessions sequentially
pool.getSession().close();
pool.getSession().close();
pool.getSession().close();
// Advance the time by running the maintainer. This should cause
// one session to be kept alive and two sessions to be removed.
long cycles = options.getRemoveInactiveSessionAfter().toMillis() / pool.poolMaintainer.loopFrequency;
runMaintenanceLoop(clock, pool, cycles);
// We will still close 2 sessions since at any point in time only 1 session was in use.
assertThat(pool.numIdleSessionsRemoved()).isEqualTo(2L);
pool.closeAsync(new SpannerImpl.ClosedException()).get(5L, TimeUnit.SECONDS);
}
use of com.google.cloud.spanner.SessionPool.PooledSessionFuture in project java-spanner by googleapis.
the class DatabaseClientImplTest method testRunAsync_usesOptions.
@Test
public void testRunAsync_usesOptions() {
SessionPool pool = mock(SessionPool.class);
PooledSessionFuture session = mock(PooledSessionFuture.class);
when(pool.getSession()).thenReturn(session);
TransactionOption option = mock(TransactionOption.class);
DatabaseClientImpl client = new DatabaseClientImpl(pool);
client.runAsync(option);
verify(session).runAsync(option);
}
Aggregations