@Override public void run() { try (Session session = pool.getReadSession()) { latch.countDown(); } } })
@Override public void run() { try (Session session3 = pool.getReadSession()) { latch.countDown(); } } })
@Override public void run() { try (Session session = pool.getReadSession()) { failed.compareAndSet(false, session == null); Uninterruptibles.sleepUninterruptibly(10, TimeUnit.MILLISECONDS); } catch (SpannerException e) { failed.compareAndSet(false, true); } finally { latch.countDown(); } } })
@Test public void sessionCreation() { try (Session session = pool.getReadSession()) { assertThat(session).isNotNull(); } try (Session session = pool.getReadSession()) { assertThat(session).isNotNull(); Session session2 = pool.getReadSession(); assertThat(session2).isNotNull(); session2.close(); } }
@Test public void closeWhenSessionsActiveFinishes() throws Exception { Session session = pool.getReadSession(); pool.closeAsync().get(); } }
@Override public ReadOnlyTransaction readOnlyTransaction() { Span span = tracer.spanBuilder(READ_ONLY_TRANSACTION).startSpan(); try (Scope s = tracer.withSpan(span)) { return pool.getReadSession().readOnlyTransaction(); } catch (RuntimeException e) { TraceUtil.endSpanWithFailure(span, e); throw e; } }
@Override public ReadOnlyTransaction singleUseReadOnlyTransaction(TimestampBound bound) { Span span = tracer.spanBuilder(READ_ONLY_TRANSACTION).startSpan(); try (Scope s = tracer.withSpan(span)) { return pool.getReadSession().singleUseReadOnlyTransaction(bound); } catch (RuntimeException e) { TraceUtil.endSpanWithFailure(span, e); throw e; } }
@Override public ReadContext singleUse() { Span span = tracer.spanBuilder(READ_ONLY_TRANSACTION).startSpan(); try (Scope s = tracer.withSpan(span)) { return pool.getReadSession().singleUse(); } catch (RuntimeException e) { TraceUtil.endSpanWithFailure(span, e); throw e; } }
@Override public ReadContext singleUse(TimestampBound bound) { Span span = tracer.spanBuilder(READ_ONLY_TRANSACTION).startSpan(); try (Scope s = tracer.withSpan(span)) { return pool.getReadSession().singleUse(bound); } catch (RuntimeException e) { TraceUtil.endSpanWithFailure(span, e); throw e; } }
@Override public ReadOnlyTransaction singleUseReadOnlyTransaction() { Span span = tracer.spanBuilder(READ_ONLY_TRANSACTION).startSpan(); try (Scope s = tracer.withSpan(span)) { return pool.getReadSession().singleUseReadOnlyTransaction(); } catch (RuntimeException e) { TraceUtil.endSpanWithFailure(span, e); throw e; } }
@Override public ReadOnlyTransaction readOnlyTransaction(TimestampBound bound) { Span span = tracer.spanBuilder(READ_ONLY_TRANSACTION).startSpan(); try (Scope s = tracer.withSpan(span)) { return pool.getReadSession().readOnlyTransaction(bound); } catch (RuntimeException e) { TraceUtil.endSpanWithFailure(span, e); throw e; } }
@Test public void poolExhaustion() throws Exception { Session session1 = pool.getReadSession(); Session session2 = pool.getReadSession(); final CountDownLatch latch = new CountDownLatch(1); new Thread( new Runnable() { @Override public void run() { try (Session session3 = pool.getReadSession()) { latch.countDown(); } } }) .start(); assertThat(latch.await(5, TimeUnit.SECONDS)).isFalse(); session1.close(); session2.close(); latch.await(); }
@Test public void multipleWaiters() throws Exception { Session session1 = pool.getReadSession(); Session session2 = pool.getReadSession(); int numSessions = 5; final CountDownLatch latch = new CountDownLatch(numSessions); for (int i = 0; i < numSessions; i++) { new Thread( new Runnable() { @Override public void run() { try (Session session = pool.getReadSession()) { latch.countDown(); } } }) .start(); } session1.close(); session2.close(); // Everyone should get session pretty quickly. assertThat(latch.await(1, TimeUnit.SECONDS)).isTrue(); }
@Test public void closeAfterInitialCreateDoesNotBlockIndefinitely() throws Exception { pool.getReadSession().close(); pool.closeAsync().get(); }
@Test public void poolClosureFailsNewRequests() throws Exception { Session session = mockSession(); when(client.createSession(db)).thenReturn(session); pool = createPool(); pool.getReadSession(); pool.closeAsync(); expectedException.expect(IllegalStateException.class); pool.getReadSession(); }
@Test public void poolClosureClosesLeakedSessions() throws Exception { Session mockSession1 = mockSession(); Session mockSession2 = mockSession(); when(client.createSession(db)).thenReturn(mockSession1).thenReturn(mockSession2); pool = createPool(); Session session1 = pool.getReadSession(); // Leaked sessions pool.getReadSession(); session1.close(); pool.closeAsync().get(); verify(mockSession1).close(); verify(mockSession2).close(); }
@Test public void sessionCreation() { setupMockSessionCreation(); pool = createPool(); try (Session session = pool.getReadSession()) { assertThat(session).isNotNull(); } }
@Test public void creationExceptionPropagatesToReadSession() { when(client.createSession(db)) .thenThrow(SpannerExceptionFactory.newSpannerException(ErrorCode.INTERNAL, "")); pool = createPool(); expectedException.expect(isSpannerException(ErrorCode.INTERNAL)); pool.getReadSession(); }
@Test public void keepAlive() throws Exception { options = SessionPoolOptions.newBuilder().setMinSessions(2).setMaxSessions(3).build(); Session session = mockSession(); mockKeepAlive(session); // This is cheating as we are returning the same session each but it makes the verification // easier. when(client.createSession(db)).thenReturn(session); FakeClock clock = new FakeClock(); clock.currentTimeMillis = System.currentTimeMillis(); pool = createPool(clock); Session session1 = pool.getReadSession(); Session session2 = pool.getReadSession(); session1.close(); session2.close(); runMaintainanceLoop(clock, pool, pool.poolMaintainer.numKeepAliveCycles); verify(session, never()).singleUse(any(TimestampBound.class)); runMaintainanceLoop(clock, pool, pool.poolMaintainer.numKeepAliveCycles); verify(session, times(2)).singleUse(any(TimestampBound.class)); clock.currentTimeMillis += clock.currentTimeMillis + 35 * 60 * 1000; session1 = pool.getReadSession(); session1.writeAtLeastOnce(new ArrayList<Mutation>()); session1.close(); runMaintainanceLoop(clock, pool, pool.poolMaintainer.numKeepAliveCycles); verify(session, times(3)).singleUse(any(TimestampBound.class)); pool.closeAsync().get(); }
@Test public void failOnPoolExhaustion() { options = SessionPoolOptions.newBuilder() .setMinSessions(1) .setMaxSessions(1) .setFailIfPoolExhausted() .build(); Session mockSession = mockSession(); when(client.createSession(db)).thenReturn(mockSession); pool = createPool(); Session session1 = pool.getReadSession(); expectedException.expect(isSpannerException(ErrorCode.RESOURCE_EXHAUSTED)); pool.getReadSession(); session1.close(); session1 = pool.getReadSession(); assertThat(session1).isNotNull(); session1.close(); }