use of java.util.concurrent.ScheduledExecutorService in project pinot by linkedin.
the class NettySingleConnectionIntegrationTest method testServerShutdownLeak.
/*
* This test attempts to use the connection mechanism the same way as ScatterGatherImpl.SingleRequestHandler does.
*
* WARNING: This test has potential failures due to timing.
*/
@Test
public void testServerShutdownLeak() throws Exception {
final NettyClientMetrics metric = new NettyClientMetrics(null, "abc");
final Timer timer = new HashedWheelTimer();
final int minConns = 2;
final int maxConns = 3;
// 10M ms.
final int maxIdleTimeoutMs = 10000000;
final int maxBacklogPerServer = 1;
MyServer server = new MyServer();
Thread.sleep(1000);
// used as a key to pool. Can be anything.
final String serverName = "SomeServer";
final ServerInstance serverInstance = server.getServerInstance();
final MetricsRegistry metricsRegistry = new MetricsRegistry();
EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
PooledNettyClientResourceManager resourceManager = new PooledNettyClientResourceManager(eventLoopGroup, new HashedWheelTimer(), metric);
ExecutorService executorService = Executors.newCachedThreadPool();
ScheduledExecutorService timeoutExecutor = new ScheduledThreadPoolExecutor(5);
AsyncPoolResourceManagerAdapter<ServerInstance, NettyClientConnection> rmAdapter = new AsyncPoolResourceManagerAdapter<ServerInstance, NettyClientConnection>(serverInstance, resourceManager, executorService, metricsRegistry);
KeyedPool<ServerInstance, NettyClientConnection> keyedPool = new KeyedPoolImpl<ServerInstance, NettyClientConnection>(minConns, maxConns, maxIdleTimeoutMs, maxBacklogPerServer, resourceManager, timeoutExecutor, executorService, metricsRegistry);
resourceManager.setPool(keyedPool);
keyedPool.start();
Field keyedPoolMap = KeyedPoolImpl.class.getDeclaredField("_keyedPool");
keyedPoolMap.setAccessible(true);
KeyedFuture<ServerInstance, NettyClientConnection> keyedFuture = keyedPool.checkoutObject(serverInstance);
// The connection pool for this server is created on demand, so we can now get a reference to the _keyedPool.
// The act of calling checkoutObject() creates a new AsyncPoolImpl and places a request for a new connection.
// Since no new connections are available in the beginning, we always end up creating one more than the min.
Map<ServerInstance, AsyncPool<NettyClientConnection>> poolMap = (Map<ServerInstance, AsyncPool<NettyClientConnection>>) keyedPoolMap.get(keyedPool);
AsyncPool<NettyClientConnection> asyncPool = poolMap.get(serverInstance);
Field waiterList = AsyncPoolImpl.class.getDeclaredField("_waiters");
waiterList.setAccessible(true);
LinkedDequeue queue = (LinkedDequeue) waiterList.get(asyncPool);
PoolStats stats;
// If the number of waiters is = 0, then we will error out because the min connections may not have completed
// by the time we check one out. If maxWaiters is > 0, then we may end up initiating a fresh connection while the
// min is still being filled. So, best to sleep a little to make sure that the min pool size is filled out, so that
// the stats are correct.
Thread.sleep(2000L);
stats = asyncPool.getStats();
Assert.assertEquals(stats.getIdleCount(), minConns);
Assert.assertEquals(stats.getPoolSize(), minConns + 1);
NettyClientConnection conn = keyedFuture.getOne();
LOGGER.debug("Got connection ID " + conn.getConnId());
Assert.assertEquals(stats.getIdleCount(), minConns);
Assert.assertEquals(stats.getPoolSize(), minConns + 1);
// Now get two more connections to the server, since we have 2 idle, we should get those.
// And leak them.
keyedFuture = keyedPool.checkoutObject(serverInstance);
conn = keyedFuture.getOne();
LOGGER.debug("Got connection ID " + conn.getConnId());
keyedFuture = keyedPool.checkoutObject(serverInstance);
conn = keyedFuture.getOne();
LOGGER.debug("Got connection ID " + conn.getConnId());
// Now we should have 0 idle, and a pool size of 3 with no waiters.
stats = asyncPool.getStats();
Assert.assertEquals(stats.getIdleCount(), 0);
Assert.assertEquals(stats.getPoolSize(), minConns + 1);
Assert.assertEquals(queue.size(), 0);
// Now, we will always get an exception because we don't have a free connection to the server.
{
keyedFuture = keyedPool.checkoutObject(serverInstance);
boolean caughtException = false;
LOGGER.debug("Will never get a connection here.");
try {
conn = keyedFuture.getOne(3, TimeUnit.SECONDS);
} catch (TimeoutException e) {
caughtException = true;
}
Assert.assertTrue(caughtException);
keyedFuture.cancel(true);
}
// Now if the server goes down, we should release all three connections and be able to get a successful new connection
LOGGER.info("Shutting down server instance");
server.shutdown();
// Give it time to clean up on the client side.
Thread.sleep(2000L);
stats = asyncPool.getStats();
LOGGER.debug(stats.toString());
// There will be a couple in idleCount in error state.
Assert.assertEquals(stats.getIdleCount(), minConns);
Assert.assertEquals(stats.getPoolSize(), minConns);
LOGGER.debug("Restarting server instance");
server.restart();
Thread.sleep(3000);
LOGGER.debug("Server restart successful\n" + asyncPool.getStats());
// Now get 3 connections successfully
for (int i = 0; i < 3; i++) {
keyedFuture = keyedPool.checkoutObject(serverInstance);
conn = keyedFuture.getOne();
Assert.assertNotNull(conn);
}
server.shutdown();
}
use of java.util.concurrent.ScheduledExecutorService in project pinot by linkedin.
the class KeyedPoolImplTest method testShutdownWhileCheckingOut.
@Test
public void testShutdownWhileCheckingOut() throws Exception {
ScheduledExecutorService timedExecutor = new ScheduledThreadPoolExecutor(1);
ExecutorService service = new ThreadPoolExecutor(1, 1, 1, TimeUnit.DAYS, new LinkedBlockingDeque<Runnable>());
int numKeys = 1;
int numResourcesPerKey = 1;
Map<String, List<String>> resources = buildCreateMap(numKeys, numResourcesPerKey);
BlockingTestResourceManager rm = new BlockingTestResourceManager(resources, null, null, null);
KeyedPool<String, String> kPool = new KeyedPoolImpl<String, String>(0, 1, 1000L, 1000 * 60 * 60, rm, timedExecutor, service, null);
kPool.start();
AsyncResponseFuture<String, String> f = (AsyncResponseFuture<String, String>) kPool.checkoutObject(getKey(0));
boolean isTimedout = false;
try {
f.get(2, TimeUnit.SECONDS);
} catch (TimeoutException e) {
isTimedout = true;
}
Assert.assertTrue(isTimedout);
kPool.shutdown().get();
// Future should have been done with error
Assert.assertNull(f.get());
Assert.assertNotNull(f.getError());
boolean cancelled = f.cancel(false);
Assert.assertFalse(cancelled);
Assert.assertFalse(f.isCancelled());
Assert.assertTrue(f.isDone());
rm.getCreateBlockLatch().countDown();
Thread.sleep(5000);
}
use of java.util.concurrent.ScheduledExecutorService in project pinot by linkedin.
the class KeyedPoolImplTest method testPoolImpl1.
@Test
public /**
* Pool contains 5 inner pools with 5 resources as max capacity
* Checkout all of them. Verify checked out is expected. Verify aggregated stats
* Checkin all of them. At each step check stats
* Checkout one from each inner pool and destroy them. Check stats
* Shutdown. Ensure clean shutdown.
* @throws Exception
*/
void testPoolImpl1() throws Exception {
ScheduledExecutorService timedExecutor = new ScheduledThreadPoolExecutor(1);
ExecutorService service = MoreExecutors.sameThreadExecutor();
int numKeys = 5;
int numResourcesPerKey = 5;
TestResourceManager rm = new TestResourceManager(buildCreateMap(numKeys, numResourcesPerKey), null, null, null);
KeyedPool<String, String> kPool = new KeyedPoolImpl<String, String>(5, 5, 1000 * 60 * 60L, 100, rm, timedExecutor, service, null);
kPool.start();
AggregatedPoolStats s = (AggregatedPoolStats) kPool.getStats();
int c = 1;
for (int j = 0; j < numResourcesPerKey; j++) {
for (int i = 0; i < numKeys; i++) {
KeyedFuture<String, String> rFuture = kPool.checkoutObject(getKey(i));
String resource = rFuture.getOne();
Assert.assertEquals(resource, getResource(i, j));
s.refresh();
Assert.assertEquals(s.getCheckedOut(), c++);
}
}
s = (AggregatedPoolStats) kPool.getStats();
Assert.assertEquals(s.getTotalCreated(), numKeys * numResourcesPerKey);
int checkedOut = c - 1;
// checkin back all
for (int j = 0; j < numResourcesPerKey; j++) {
for (int i = 0; i < numKeys; i++) {
kPool.checkinObject(getKey(i), getResource(i, j));
s.refresh();
Assert.assertEquals(s.getCheckedOut(), --checkedOut);
}
}
s = (AggregatedPoolStats) kPool.getStats();
// checkout one from each and destroy them
c = 1;
int d = 1;
for (int i = 0; i < numKeys; i++) {
KeyedFuture<String, String> rFuture = kPool.checkoutObject(getKey(i));
String resource = rFuture.getOne();
Assert.assertEquals(resource, getResource(i, 0));
CountDownLatch latch = new CountDownLatch(1);
rm.setCountDownLatch(latch);
kPool.destroyObject(getKey(i), resource);
latch.await();
Thread.sleep(1000);
s.refresh();
Assert.assertEquals(s.getCheckedOut(), 0);
Assert.assertEquals(s.getTotalDestroyed(), d++);
}
Future<Map<String, NoneType>> f = kPool.shutdown();
f.get();
//Verify all objects are destroyed
Map<String, List<String>> destroyedMap = rm.getDestroyedMap();
Assert.assertEquals(destroyedMap.keySet().size(), numKeys);
for (int i = 0; i < numKeys; i++) {
List<String> r = destroyedMap.get(getKey(i));
Assert.assertEquals(r.size(), numResourcesPerKey, "Resource for Key (" + getKey(i) + ")");
for (int j = 0; j < numResourcesPerKey; j++) {
Assert.assertTrue(r.contains(getResource(i, j)));
}
}
}
use of java.util.concurrent.ScheduledExecutorService in project pinot by linkedin.
the class KeyedPoolImplTest method testInvalidCheckinDestroy.
@Test
public void testInvalidCheckinDestroy() throws Exception {
ScheduledExecutorService timedExecutor = new ScheduledThreadPoolExecutor(1);
ExecutorService service = new ThreadPoolExecutor(1, 1, 1, TimeUnit.DAYS, new LinkedBlockingDeque<Runnable>());
int numKeys = 1;
int numResourcesPerKey = 1;
Map<String, List<String>> resources = buildCreateMap(numKeys, numResourcesPerKey);
TestResourceManager rm = new TestResourceManager(resources, null, null, null);
KeyedPool<String, String> kPool = new KeyedPoolImpl<String, String>(0, 1, 1000L, 1000 * 60 * 60, rm, timedExecutor, service, null);
kPool.start();
AsyncResponseFuture<String, String> f = (AsyncResponseFuture<String, String>) kPool.checkoutObject(getKey(0));
String s1 = f.getOne();
// checkin with invalid key
boolean isException = false;
try {
kPool.checkinObject(getKey(1), s1);
} catch (IllegalStateException e) {
isException = true;
}
Assert.assertTrue(isException);
// destroy with invalid key
isException = false;
try {
kPool.destroyObject(getKey(1), s1);
} catch (IllegalStateException e) {
isException = true;
}
Assert.assertTrue(isException);
}
use of java.util.concurrent.ScheduledExecutorService in project pinot by linkedin.
the class KeyedPoolImplTest method testCancelAfterCheckingOut.
@Test
public void testCancelAfterCheckingOut() throws Exception {
ScheduledExecutorService timedExecutor = new ScheduledThreadPoolExecutor(1);
ExecutorService service = new ThreadPoolExecutor(1, 1, 1, TimeUnit.DAYS, new LinkedBlockingDeque<Runnable>());
int numKeys = 1;
int numResourcesPerKey = 1;
Map<String, List<String>> resources = buildCreateMap(numKeys, numResourcesPerKey);
BlockingTestResourceManager rm = new BlockingTestResourceManager(resources, null, null, null);
KeyedPool<String, String> kPool = new KeyedPoolImpl<String, String>(0, 1, 1000L, 1000 * 60 * 60, rm, timedExecutor, service, null);
kPool.start();
AsyncResponseFuture<String, String> f = (AsyncResponseFuture<String, String>) kPool.checkoutObject(getKey(0));
boolean isTimedout = false;
try {
f.get(2, TimeUnit.SECONDS);
} catch (TimeoutException e) {
isTimedout = true;
}
Assert.assertTrue(isTimedout);
boolean cancelled = f.cancel(false);
Assert.assertTrue(cancelled);
Assert.assertTrue(f.isCancelled());
Assert.assertTrue(f.isDone());
rm.getCreateBlockLatch().countDown();
kPool.shutdown().get();
}
Aggregations