use of io.questdb.cutlass.http.processors.HealthCheckProcessor in project questdb by bluestreak01.
the class IODispatcherTest method testMaxConnections.
@Test
public void testMaxConnections() throws Exception {
LOG.info().$("started maxConnections").$();
assertMemoryLeak(() -> {
HttpServerConfiguration httpServerConfiguration = new DefaultHttpServerConfiguration();
final int listenBackLog = 10;
final int activeConnectionLimit = 5;
final int nExcessConnections = 20;
AtomicInteger openCount = new AtomicInteger(0);
AtomicInteger closeCount = new AtomicInteger(0);
final IODispatcherConfiguration configuration = new DefaultIODispatcherConfiguration() {
@Override
public int getActiveConnectionLimit() {
return activeConnectionLimit;
}
@Override
public int getListenBacklog() {
return listenBackLog;
}
@Override
public long getQueuedConnectionTimeout() {
return 300_000;
}
};
try (IODispatcher<HttpConnectionContext> dispatcher = IODispatchers.create(configuration, new IOContextFactory<HttpConnectionContext>() {
@SuppressWarnings("resource")
@Override
public HttpConnectionContext newInstance(long fd, IODispatcher<HttpConnectionContext> dispatcher1) {
openCount.incrementAndGet();
return new HttpConnectionContext(httpServerConfiguration.getHttpContextConfiguration()) {
@Override
public void close() {
closeCount.incrementAndGet();
super.close();
}
}.of(fd, dispatcher1);
}
})) {
HttpRequestProcessorSelector selector = new HttpRequestProcessorSelector() {
@Override
public HttpRequestProcessor select(CharSequence url) {
return null;
}
@Override
public HttpRequestProcessor getDefaultProcessor() {
return new HealthCheckProcessor();
}
@Override
public void close() {
}
};
AtomicBoolean serverRunning = new AtomicBoolean(true);
SOCountDownLatch serverHaltLatch = new SOCountDownLatch(1);
new Thread(() -> {
try {
do {
dispatcher.run(0);
dispatcher.processIOQueue((operation, context) -> context.handleClientOperation(operation, selector, EmptyRescheduleContext));
} while (serverRunning.get());
} finally {
serverHaltLatch.countDown();
}
}).start();
LongList openFds = new LongList();
LongHashSet closedFds = new LongHashSet();
final long sockAddr = Net.sockaddr("127.0.0.1", 9001);
final long buf = Unsafe.malloc(4096, MemoryTag.NATIVE_DEFAULT);
final int N = activeConnectionLimit + listenBackLog;
try {
for (int i = 0; i < N; i++) {
long fd = Net.socketTcp(true);
TestUtils.assertConnect(fd, sockAddr);
openFds.add(fd);
}
// let dispatcher catchup
long startNanos = System.nanoTime();
while (dispatcher.isListening()) {
long endNanos = System.nanoTime();
if (TimeUnit.NANOSECONDS.toSeconds(endNanos - startNanos) > 30) {
Assert.fail("Timed out waiting for despatcher to stop listening");
}
LockSupport.parkNanos(1);
}
final String request = "GET /status?x=1&a=%26b&c&d=x HTTP/1.1\r\n" + "Host: localhost:9000\r\n" + "Connection: keep-alive\r\n" + "Cache-Control: max-age=0\r\n" + "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8\r\n" + "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.48 Safari/537.36\r\n" + "Accept-Encoding: gzip,deflate,sdch\r\n" + "Accept-Language: en-US,en;q=0.8\r\n" + "Cookie: textwrapon=false; textautoformat=false; wysiwyg=textarea\r\n" + "\r\n";
long mem = TestUtils.toMemory(request);
// Active connection limit is reached and backlog is full, check we get connection closed
for (int i = 0; i < nExcessConnections; i++) {
long fd = Net.socketTcp(true);
if (fd > 0) {
int nSent = Net.send(fd, mem, request.length());
Assert.assertTrue(nSent < 0);
Net.close(fd);
}
}
try {
for (int i = 0; i < N; i++) {
if (i == activeConnectionLimit) {
for (int j = 0; j < activeConnectionLimit; j++) {
long fd = openFds.getQuick(j);
Net.close(fd);
closedFds.add(fd);
}
}
long fd = openFds.getQuick(i);
Assert.assertEquals(request.length(), Net.send(fd, mem, request.length()));
// ensure we have response from server
Assert.assertTrue(0 < Net.recv(fd, buf, 64));
if (i < activeConnectionLimit) {
// dont close any connections until the first connections have been processed and check that the dispatcher
// is not listening
Assert.assertFalse(dispatcher.isListening());
} else {
Net.close(fd);
closedFds.add(fd);
}
}
} finally {
Unsafe.free(mem, request.length(), MemoryTag.NATIVE_DEFAULT);
}
} finally {
for (int i = 0; i < openFds.size(); i++) {
long fd = openFds.getQuick(i);
if (!closedFds.contains(fd)) {
Net.close(fd);
}
}
Net.freeSockAddr(sockAddr);
Unsafe.free(buf, 4096, MemoryTag.NATIVE_DEFAULT);
Assert.assertFalse(configuration.getActiveConnectionLimit() < dispatcher.getConnectionCount());
serverRunning.set(false);
serverHaltLatch.await();
}
}
});
}
Aggregations