Search in sources :

Example 1 with DefaultIODispatcherConfiguration

use of io.questdb.network.DefaultIODispatcherConfiguration in project questdb by bluestreak01.

the class IODispatcherTest method testSendHttpGetAndSimpleResponse.

@Test
public void testSendHttpGetAndSimpleResponse() throws Exception {
    LOG.info().$("started testSendHttpGetAndSimpleResponse").$();
    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";
    // the difference between request and expected is url encoding (and ':' padding, which can easily be fixed)
    final String expected = "GET /status?x=1&a=&b&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";
    final String expectedResponse = "HTTP/1.1 200 OK\r\n" + "Server: questDB/1.0\r\n" + "Date: Thu, 1 Jan 1970 00:00:00 GMT\r\n" + "Transfer-Encoding: chunked\r\n" + "Content-Type: text/plain; charset=utf-8\r\n" + "\r\n" + "04\r\n" + "OK\r\n" + "\r\n" + "00\r\n" + "\r\n";
    assertMemoryLeak(() -> {
        HttpServerConfiguration httpServerConfiguration = new DefaultHttpServerConfiguration(new DefaultHttpContextConfiguration() {

            @Override
            public MillisecondClock getClock() {
                return () -> 0;
            }
        });
        SOCountDownLatch connectLatch = new SOCountDownLatch(1);
        SOCountDownLatch contextClosedLatch = new SOCountDownLatch(1);
        AtomicInteger closeCount = new AtomicInteger(0);
        try (IODispatcher<HttpConnectionContext> dispatcher = IODispatchers.create(new DefaultIODispatcherConfiguration(), new IOContextFactory<HttpConnectionContext>() {

            @Override
            public HttpConnectionContext newInstance(long fd, IODispatcher<HttpConnectionContext> dispatcher1) {
                connectLatch.countDown();
                return new HttpConnectionContext(httpServerConfiguration.getHttpContextConfiguration()) {

                    @Override
                    public void close() {
                        // context is closed
                        if (closeCount.incrementAndGet() == 1) {
                            super.close();
                            contextClosedLatch.countDown();
                        }
                    }
                }.of(fd, dispatcher1);
            }
        })) {
            StringSink sink = new StringSink();
            final HttpRequestProcessorSelector selector = new HttpRequestProcessorSelector() {

                @Override
                public HttpRequestProcessor select(CharSequence url) {
                    return null;
                }

                @Override
                public HttpRequestProcessor getDefaultProcessor() {
                    return new HttpRequestProcessor() {

                        @Override
                        public void onHeadersReady(HttpConnectionContext context) {
                            HttpRequestHeader headers = context.getRequestHeader();
                            sink.put(headers.getMethodLine());
                            sink.put("\r\n");
                            ObjList<CharSequence> headerNames = headers.getHeaderNames();
                            for (int i = 0, n = headerNames.size(); i < n; i++) {
                                sink.put(headerNames.getQuick(i)).put(':');
                                sink.put(headers.getHeader(headerNames.getQuick(i)));
                                sink.put("\r\n");
                            }
                            sink.put("\r\n");
                        }

                        @Override
                        public void onRequestComplete(HttpConnectionContext context) throws PeerDisconnectedException, PeerIsSlowToReadException {
                            context.simpleResponse().sendStatusWithDefaultMessage(200);
                        }
                    };
                }

                @Override
                public void close() {
                }
            };
            AtomicBoolean serverRunning = new AtomicBoolean(true);
            SOCountDownLatch serverHaltLatch = new SOCountDownLatch(1);
            new Thread(() -> {
                while (serverRunning.get()) {
                    dispatcher.run(0);
                    dispatcher.processIOQueue((operation, context) -> context.handleClientOperation(operation, selector, EmptyRescheduleContext));
                }
                serverHaltLatch.countDown();
            }).start();
            long fd = Net.socketTcp(true);
            try {
                long sockAddr = Net.sockaddr("127.0.0.1", 9001);
                try {
                    TestUtils.assertConnect(fd, sockAddr);
                    connectLatch.await();
                    int len = request.length();
                    long buffer = TestUtils.toMemory(request);
                    try {
                        Assert.assertEquals(len, Net.send(fd, buffer, len));
                        // read response we expect
                        StringSink sink2 = new StringSink();
                        final int expectedLen = expectedResponse.length();
                        int read = 0;
                        while (read < expectedLen) {
                            int n = Net.recv(fd, buffer, len);
                            Assert.assertTrue(n > 0);
                            for (int i = 0; i < n; i++) {
                                sink2.put((char) Unsafe.getUnsafe().getByte(buffer + i));
                            }
                            // copy response bytes to sink
                            read += n;
                        }
                        TestUtils.assertEquals(expectedResponse, sink2);
                    } finally {
                        Unsafe.free(buffer, len, MemoryTag.NATIVE_DEFAULT);
                    }
                    Assert.assertEquals(0, Net.close(fd));
                    LOG.info().$("closed [fd=").$(fd).$(']').$();
                    fd = -1;
                    contextClosedLatch.await();
                    serverRunning.set(false);
                    serverHaltLatch.await();
                    Assert.assertEquals(0, dispatcher.getConnectionCount());
                    TestUtils.assertEquals(expected, sink);
                } finally {
                    Net.freeSockAddr(sockAddr);
                }
            } finally {
                if (fd != -1) {
                    Net.close(fd);
                }
            }
            Assert.assertEquals(1, closeCount.get());
        }
    });
}
Also used : IOOperation(io.questdb.network.IOOperation) DefaultIODispatcherConfiguration(io.questdb.network.DefaultIODispatcherConfiguration) Log(io.questdb.log.Log) WorkerPoolConfiguration(io.questdb.mp.WorkerPoolConfiguration) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) TestUtils.assertMemoryLeak(io.questdb.test.tools.TestUtils.assertMemoryLeak) WorkerPool(io.questdb.mp.WorkerPool) Timestamps(io.questdb.std.datetime.microtime.Timestamps) TestLatchedCounterFunctionFactory(io.questdb.griffin.engine.functions.test.TestLatchedCounterFunctionFactory) QueryCache(io.questdb.cutlass.http.processors.QueryCache) io.questdb.std(io.questdb.std) IODispatchers(io.questdb.network.IODispatchers) CyclicBarrier(java.util.concurrent.CyclicBarrier) SOCountDownLatch(io.questdb.mp.SOCountDownLatch) LockSupport(java.util.concurrent.locks.LockSupport) StaticContentProcessor(io.questdb.cutlass.http.processors.StaticContentProcessor) CountDownLatch(java.util.concurrent.CountDownLatch) Path(io.questdb.std.str.Path) io.questdb.cairo(io.questdb.cairo) AllowAllCairoSecurityContext(io.questdb.cairo.security.AllowAllCairoSecurityContext) IORequestProcessor(io.questdb.network.IORequestProcessor) NotNull(org.jetbrains.annotations.NotNull) JsonQueryProcessor(io.questdb.cutlass.http.processors.JsonQueryProcessor) TextImportProcessor(io.questdb.cutlass.http.processors.TextImportProcessor) IODispatcher(io.questdb.network.IODispatcher) AbstractCharSequence(io.questdb.std.str.AbstractCharSequence) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) MPSequence(io.questdb.mp.MPSequence) IOContextFactory(io.questdb.network.IOContextFactory) NetUtils(io.questdb.cutlass.NetUtils) SqlException(io.questdb.griffin.SqlException) SCSequence(io.questdb.mp.SCSequence) IOContext(io.questdb.network.IOContext) TestUtils(io.questdb.test.tools.TestUtils) SqlCompiler(io.questdb.griffin.SqlCompiler) LogFactory(io.questdb.log.LogFactory) Metrics(io.questdb.Metrics) HealthCheckProcessor(io.questdb.cutlass.http.processors.HealthCheckProcessor) NetworkFacadeImpl(io.questdb.network.NetworkFacadeImpl) SqlExecutionContextImpl(io.questdb.griffin.SqlExecutionContextImpl) NetworkFacade(io.questdb.network.NetworkFacade) RingQueue(io.questdb.mp.RingQueue) PeerDisconnectedException(io.questdb.network.PeerDisconnectedException) TimeUnit(java.util.concurrent.TimeUnit) SharedRandom(io.questdb.griffin.engine.functions.rnd.SharedRandom) AtomicLong(java.util.concurrent.atomic.AtomicLong) PeerIsSlowToReadException(io.questdb.network.PeerIsSlowToReadException) StringSink(io.questdb.std.str.StringSink) Net(io.questdb.network.Net) MillisecondClock(io.questdb.std.datetime.millitime.MillisecondClock) IODispatcherConfiguration(io.questdb.network.IODispatcherConfiguration) org.junit(org.junit) SqlExecutionContext(io.questdb.griffin.SqlExecutionContext) TemporaryFolder(org.junit.rules.TemporaryFolder) ByteSequence(io.questdb.std.str.ByteSequence) InputStream(java.io.InputStream) AbstractCharSequence(io.questdb.std.str.AbstractCharSequence) StringSink(io.questdb.std.str.StringSink) SOCountDownLatch(io.questdb.mp.SOCountDownLatch) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) DefaultIODispatcherConfiguration(io.questdb.network.DefaultIODispatcherConfiguration) MillisecondClock(io.questdb.std.datetime.millitime.MillisecondClock)

Example 2 with DefaultIODispatcherConfiguration

use of io.questdb.network.DefaultIODispatcherConfiguration 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();
            }
        }
    });
}
Also used : IOOperation(io.questdb.network.IOOperation) DefaultIODispatcherConfiguration(io.questdb.network.DefaultIODispatcherConfiguration) Log(io.questdb.log.Log) WorkerPoolConfiguration(io.questdb.mp.WorkerPoolConfiguration) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) TestUtils.assertMemoryLeak(io.questdb.test.tools.TestUtils.assertMemoryLeak) WorkerPool(io.questdb.mp.WorkerPool) Timestamps(io.questdb.std.datetime.microtime.Timestamps) TestLatchedCounterFunctionFactory(io.questdb.griffin.engine.functions.test.TestLatchedCounterFunctionFactory) QueryCache(io.questdb.cutlass.http.processors.QueryCache) io.questdb.std(io.questdb.std) IODispatchers(io.questdb.network.IODispatchers) CyclicBarrier(java.util.concurrent.CyclicBarrier) SOCountDownLatch(io.questdb.mp.SOCountDownLatch) LockSupport(java.util.concurrent.locks.LockSupport) StaticContentProcessor(io.questdb.cutlass.http.processors.StaticContentProcessor) CountDownLatch(java.util.concurrent.CountDownLatch) Path(io.questdb.std.str.Path) io.questdb.cairo(io.questdb.cairo) AllowAllCairoSecurityContext(io.questdb.cairo.security.AllowAllCairoSecurityContext) IORequestProcessor(io.questdb.network.IORequestProcessor) NotNull(org.jetbrains.annotations.NotNull) JsonQueryProcessor(io.questdb.cutlass.http.processors.JsonQueryProcessor) TextImportProcessor(io.questdb.cutlass.http.processors.TextImportProcessor) IODispatcher(io.questdb.network.IODispatcher) AbstractCharSequence(io.questdb.std.str.AbstractCharSequence) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) MPSequence(io.questdb.mp.MPSequence) IOContextFactory(io.questdb.network.IOContextFactory) NetUtils(io.questdb.cutlass.NetUtils) SqlException(io.questdb.griffin.SqlException) SCSequence(io.questdb.mp.SCSequence) IOContext(io.questdb.network.IOContext) TestUtils(io.questdb.test.tools.TestUtils) SqlCompiler(io.questdb.griffin.SqlCompiler) LogFactory(io.questdb.log.LogFactory) Metrics(io.questdb.Metrics) HealthCheckProcessor(io.questdb.cutlass.http.processors.HealthCheckProcessor) NetworkFacadeImpl(io.questdb.network.NetworkFacadeImpl) SqlExecutionContextImpl(io.questdb.griffin.SqlExecutionContextImpl) NetworkFacade(io.questdb.network.NetworkFacade) RingQueue(io.questdb.mp.RingQueue) PeerDisconnectedException(io.questdb.network.PeerDisconnectedException) TimeUnit(java.util.concurrent.TimeUnit) SharedRandom(io.questdb.griffin.engine.functions.rnd.SharedRandom) AtomicLong(java.util.concurrent.atomic.AtomicLong) PeerIsSlowToReadException(io.questdb.network.PeerIsSlowToReadException) StringSink(io.questdb.std.str.StringSink) Net(io.questdb.network.Net) MillisecondClock(io.questdb.std.datetime.millitime.MillisecondClock) IODispatcherConfiguration(io.questdb.network.IODispatcherConfiguration) org.junit(org.junit) SqlExecutionContext(io.questdb.griffin.SqlExecutionContext) TemporaryFolder(org.junit.rules.TemporaryFolder) ByteSequence(io.questdb.std.str.ByteSequence) InputStream(java.io.InputStream) DefaultIODispatcherConfiguration(io.questdb.network.DefaultIODispatcherConfiguration) IODispatcherConfiguration(io.questdb.network.IODispatcherConfiguration) AbstractCharSequence(io.questdb.std.str.AbstractCharSequence) SOCountDownLatch(io.questdb.mp.SOCountDownLatch) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) DefaultIODispatcherConfiguration(io.questdb.network.DefaultIODispatcherConfiguration) HealthCheckProcessor(io.questdb.cutlass.http.processors.HealthCheckProcessor)

Example 3 with DefaultIODispatcherConfiguration

use of io.questdb.network.DefaultIODispatcherConfiguration in project questdb by bluestreak01.

the class IODispatcherTest method testCannotSetNonBlocking.

@Test
public void testCannotSetNonBlocking() throws Exception {
    assertMemoryLeak(() -> {
        final HttpContextConfiguration httpContextConfiguration = new DefaultHttpContextConfiguration();
        final NetworkFacade nf = new NetworkFacadeImpl() {

            long theFd;

            @Override
            public long accept(long serverFd) {
                long fd = super.accept(serverFd);
                theFd = fd;
                return fd;
            }

            @Override
            public int configureNonBlocking(long fd) {
                if (fd == theFd) {
                    return -1;
                }
                return super.configureNonBlocking(fd);
            }
        };
        try (IODispatcher<HttpConnectionContext> dispatcher = IODispatchers.create(new DefaultIODispatcherConfiguration() {

            @Override
            public NetworkFacade getNetworkFacade() {
                return nf;
            }
        }, (fd, dispatcher1) -> new HttpConnectionContext(httpContextConfiguration).of(fd, dispatcher1))) {
            // spin up dispatcher thread
            AtomicBoolean dispatcherRunning = new AtomicBoolean(true);
            SOCountDownLatch dispatcherHaltLatch = new SOCountDownLatch(1);
            new Thread(() -> {
                while (dispatcherRunning.get()) {
                    dispatcher.run(0);
                }
                dispatcherHaltLatch.countDown();
            }).start();
            try {
                long socketAddr = Net.sockaddr(Net.parseIPv4("127.0.0.1"), 9001);
                long fd = Net.socketTcp(true);
                try {
                    TestUtils.assertConnect(fd, socketAddr);
                    int bufLen = 512;
                    long mem = Unsafe.malloc(bufLen, MemoryTag.NATIVE_DEFAULT);
                    try {
                        Assert.assertEquals(-2, Net.recv(fd, mem, bufLen));
                    } finally {
                        Unsafe.free(mem, bufLen, MemoryTag.NATIVE_DEFAULT);
                    }
                } finally {
                    Net.close(fd);
                    Net.freeSockAddr(socketAddr);
                }
            } finally {
                dispatcherRunning.set(false);
                dispatcherHaltLatch.await();
            }
        }
    });
}
Also used : NetworkFacade(io.questdb.network.NetworkFacade) SOCountDownLatch(io.questdb.mp.SOCountDownLatch) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) DefaultIODispatcherConfiguration(io.questdb.network.DefaultIODispatcherConfiguration) NetworkFacadeImpl(io.questdb.network.NetworkFacadeImpl)

Example 4 with DefaultIODispatcherConfiguration

use of io.questdb.network.DefaultIODispatcherConfiguration in project questdb by bluestreak01.

the class IODispatcherTest method testTwoThreadsSendTwoThreadsRead.

@Test
public // dispatcher or Http parser.
void testTwoThreadsSendTwoThreadsRead() throws Exception {
    LOG.info().$("started testSendHttpGet").$();
    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";
    // the difference between request and expected is url encoding (and ':' padding, which can easily be fixed)
    final String expected = "GET /status?x=1&a=&b&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";
    final int N = 100;
    final int serverThreadCount = 2;
    final int senderCount = 2;
    assertMemoryLeak(() -> {
        HttpServerConfiguration httpServerConfiguration = new DefaultHttpServerConfiguration();
        final NetworkFacade nf = NetworkFacadeImpl.INSTANCE;
        final AtomicInteger requestsReceived = new AtomicInteger();
        final AtomicBoolean finished = new AtomicBoolean(false);
        final SOCountDownLatch senderHalt = new SOCountDownLatch(senderCount);
        try (IODispatcher<HttpConnectionContext> dispatcher = IODispatchers.create(new DefaultIODispatcherConfiguration(), (fd, dispatcher1) -> new HttpConnectionContext(httpServerConfiguration.getHttpContextConfiguration()).of(fd, dispatcher1))) {
            // server will publish status of each request to this queue
            final RingQueue<Status> queue = new RingQueue<>(Status::new, 1024);
            final MPSequence pubSeq = new MPSequence(queue.getCycle());
            SCSequence subSeq = new SCSequence();
            pubSeq.then(subSeq).then(pubSeq);
            final AtomicBoolean serverRunning = new AtomicBoolean(true);
            final SOCountDownLatch serverHaltLatch = new SOCountDownLatch(serverThreadCount);
            try {
                for (int j = 0; j < serverThreadCount; j++) {
                    new Thread(() -> {
                        final StringSink sink = new StringSink();
                        final long responseBuf = Unsafe.malloc(32, MemoryTag.NATIVE_DEFAULT);
                        Unsafe.getUnsafe().putByte(responseBuf, (byte) 'A');
                        final HttpRequestProcessor processor = new HttpRequestProcessor() {

                            @Override
                            public void onHeadersReady(HttpConnectionContext context) {
                                HttpRequestHeader headers = context.getRequestHeader();
                                sink.clear();
                                sink.put(headers.getMethodLine());
                                sink.put("\r\n");
                                ObjList<CharSequence> headerNames = headers.getHeaderNames();
                                for (int i = 0, n = headerNames.size(); i < n; i++) {
                                    sink.put(headerNames.getQuick(i)).put(':');
                                    sink.put(headers.getHeader(headerNames.getQuick(i)));
                                    sink.put("\r\n");
                                }
                                sink.put("\r\n");
                                boolean result;
                                try {
                                    TestUtils.assertEquals(expected, sink);
                                    result = true;
                                } catch (Exception e) {
                                    result = false;
                                }
                                while (true) {
                                    long cursor = pubSeq.next();
                                    if (cursor < 0) {
                                        continue;
                                    }
                                    queue.get(cursor).valid = result;
                                    pubSeq.done(cursor);
                                    break;
                                }
                                requestsReceived.incrementAndGet();
                                nf.send(context.getFd(), responseBuf, 1);
                            }
                        };
                        HttpRequestProcessorSelector selector = new HttpRequestProcessorSelector() {

                            @Override
                            public HttpRequestProcessor select(CharSequence url) {
                                return null;
                            }

                            @Override
                            public HttpRequestProcessor getDefaultProcessor() {
                                return processor;
                            }

                            @Override
                            public void close() {
                            }
                        };
                        while (serverRunning.get()) {
                            dispatcher.run(0);
                            dispatcher.processIOQueue((operation, context) -> context.handleClientOperation(operation, selector, EmptyRescheduleContext));
                        }
                        Unsafe.free(responseBuf, 32, MemoryTag.NATIVE_DEFAULT);
                        serverHaltLatch.countDown();
                    }).start();
                }
                AtomicInteger completedCount = new AtomicInteger();
                for (int j = 0; j < senderCount; j++) {
                    int k = j;
                    new Thread(() -> {
                        long sockAddr = Net.sockaddr("127.0.0.1", 9001);
                        try {
                            for (int i = 0; i < N && !finished.get(); i++) {
                                long fd = Net.socketTcp(true);
                                try {
                                    TestUtils.assertConnect(fd, sockAddr);
                                    int len = request.length();
                                    long buffer = TestUtils.toMemory(request);
                                    try {
                                        Assert.assertEquals(len, Net.send(fd, buffer, len));
                                        Assert.assertEquals("fd=" + fd + ", i=" + i, 1, Net.recv(fd, buffer, 1));
                                        LOG.info().$("i=").$(i).$(", j=").$(k).$();
                                        Assert.assertEquals('A', Unsafe.getUnsafe().getByte(buffer));
                                    } finally {
                                        Unsafe.free(buffer, len, MemoryTag.NATIVE_DEFAULT);
                                    }
                                } finally {
                                    Net.close(fd);
                                }
                            }
                        } finally {
                            completedCount.incrementAndGet();
                            Net.freeSockAddr(sockAddr);
                            senderHalt.countDown();
                        }
                    }).start();
                }
                int receiveCount = 0;
                while (receiveCount < N * senderCount) {
                    long cursor = subSeq.next();
                    if (cursor < 0) {
                        if (cursor == -1 && completedCount.get() == senderCount) {
                            Assert.fail("Not all requests successful, test failed, see previous failures");
                            break;
                        }
                        Thread.yield();
                        continue;
                    }
                    boolean valid = queue.get(cursor).valid;
                    subSeq.done(cursor);
                    Assert.assertTrue(valid);
                    receiveCount++;
                }
            } catch (Throwable e) {
                e.printStackTrace();
                throw e;
            } finally {
                serverRunning.set(false);
                serverHaltLatch.await();
            }
        } catch (Throwable e) {
            e.printStackTrace();
            throw e;
        } finally {
            finished.set(true);
            senderHalt.await();
        }
        Assert.assertEquals(N * senderCount, requestsReceived.get());
    });
}
Also used : MPSequence(io.questdb.mp.MPSequence) IOOperation(io.questdb.network.IOOperation) DefaultIODispatcherConfiguration(io.questdb.network.DefaultIODispatcherConfiguration) Log(io.questdb.log.Log) WorkerPoolConfiguration(io.questdb.mp.WorkerPoolConfiguration) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) TestUtils.assertMemoryLeak(io.questdb.test.tools.TestUtils.assertMemoryLeak) WorkerPool(io.questdb.mp.WorkerPool) Timestamps(io.questdb.std.datetime.microtime.Timestamps) TestLatchedCounterFunctionFactory(io.questdb.griffin.engine.functions.test.TestLatchedCounterFunctionFactory) QueryCache(io.questdb.cutlass.http.processors.QueryCache) io.questdb.std(io.questdb.std) IODispatchers(io.questdb.network.IODispatchers) CyclicBarrier(java.util.concurrent.CyclicBarrier) SOCountDownLatch(io.questdb.mp.SOCountDownLatch) LockSupport(java.util.concurrent.locks.LockSupport) StaticContentProcessor(io.questdb.cutlass.http.processors.StaticContentProcessor) CountDownLatch(java.util.concurrent.CountDownLatch) Path(io.questdb.std.str.Path) io.questdb.cairo(io.questdb.cairo) AllowAllCairoSecurityContext(io.questdb.cairo.security.AllowAllCairoSecurityContext) IORequestProcessor(io.questdb.network.IORequestProcessor) NotNull(org.jetbrains.annotations.NotNull) JsonQueryProcessor(io.questdb.cutlass.http.processors.JsonQueryProcessor) TextImportProcessor(io.questdb.cutlass.http.processors.TextImportProcessor) IODispatcher(io.questdb.network.IODispatcher) AbstractCharSequence(io.questdb.std.str.AbstractCharSequence) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) MPSequence(io.questdb.mp.MPSequence) IOContextFactory(io.questdb.network.IOContextFactory) NetUtils(io.questdb.cutlass.NetUtils) SqlException(io.questdb.griffin.SqlException) SCSequence(io.questdb.mp.SCSequence) IOContext(io.questdb.network.IOContext) TestUtils(io.questdb.test.tools.TestUtils) SqlCompiler(io.questdb.griffin.SqlCompiler) LogFactory(io.questdb.log.LogFactory) Metrics(io.questdb.Metrics) HealthCheckProcessor(io.questdb.cutlass.http.processors.HealthCheckProcessor) NetworkFacadeImpl(io.questdb.network.NetworkFacadeImpl) SqlExecutionContextImpl(io.questdb.griffin.SqlExecutionContextImpl) NetworkFacade(io.questdb.network.NetworkFacade) RingQueue(io.questdb.mp.RingQueue) PeerDisconnectedException(io.questdb.network.PeerDisconnectedException) TimeUnit(java.util.concurrent.TimeUnit) SharedRandom(io.questdb.griffin.engine.functions.rnd.SharedRandom) AtomicLong(java.util.concurrent.atomic.AtomicLong) PeerIsSlowToReadException(io.questdb.network.PeerIsSlowToReadException) StringSink(io.questdb.std.str.StringSink) Net(io.questdb.network.Net) MillisecondClock(io.questdb.std.datetime.millitime.MillisecondClock) IODispatcherConfiguration(io.questdb.network.IODispatcherConfiguration) org.junit(org.junit) SqlExecutionContext(io.questdb.griffin.SqlExecutionContext) TemporaryFolder(org.junit.rules.TemporaryFolder) ByteSequence(io.questdb.std.str.ByteSequence) InputStream(java.io.InputStream) RingQueue(io.questdb.mp.RingQueue) NetworkFacade(io.questdb.network.NetworkFacade) AbstractCharSequence(io.questdb.std.str.AbstractCharSequence) StringSink(io.questdb.std.str.StringSink) SqlException(io.questdb.griffin.SqlException) PeerDisconnectedException(io.questdb.network.PeerDisconnectedException) PeerIsSlowToReadException(io.questdb.network.PeerIsSlowToReadException) SOCountDownLatch(io.questdb.mp.SOCountDownLatch) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) SCSequence(io.questdb.mp.SCSequence) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) DefaultIODispatcherConfiguration(io.questdb.network.DefaultIODispatcherConfiguration)

Example 5 with DefaultIODispatcherConfiguration

use of io.questdb.network.DefaultIODispatcherConfiguration in project questdb by bluestreak01.

the class IODispatcherTest method testQueuedConnectionTimeout.

@Test
public void testQueuedConnectionTimeout() throws Exception {
    LOG.info().$("started testQueuedConnectionTimeout").$();
    assertMemoryLeak(() -> {
        final int listenBackLog = 10;
        final int activeConnectionLimit = 5;
        final long queuedConnectionTimeoutInMs = 250;
        final IODispatcherConfiguration configuration = new DefaultIODispatcherConfiguration() {

            @Override
            public int getActiveConnectionLimit() {
                return activeConnectionLimit;
            }

            @Override
            public int getListenBacklog() {
                return listenBackLog;
            }

            @Override
            public long getQueuedConnectionTimeout() {
                return queuedConnectionTimeoutInMs;
            }
        };
        final AtomicInteger nConnected = new AtomicInteger();
        final LongHashSet serverConnectedFds = new LongHashSet();
        final LongHashSet clientActiveFds = new LongHashSet();
        IOContextFactory<IOContext> contextFactory = (fd, dispatcher) -> {
            LOG.info().$(fd).$(" connected").$();
            serverConnectedFds.add(fd);
            nConnected.incrementAndGet();
            return new IOContext() {

                @Override
                public boolean invalid() {
                    return !serverConnectedFds.contains(fd);
                }

                @Override
                public long getFd() {
                    return fd;
                }

                @Override
                public IODispatcher<?> getDispatcher() {
                    return dispatcher;
                }

                @Override
                public void close() {
                    LOG.info().$(fd).$(" disconnected").$();
                    serverConnectedFds.remove(fd);
                }
            };
        };
        final String request = "\n";
        long mem = TestUtils.toMemory(request);
        final long sockAddr = Net.sockaddr("127.0.0.1", 9001);
        Thread serverThread;
        final CountDownLatch serverLatch = new CountDownLatch(1);
        try (IODispatcher<IOContext> dispatcher = IODispatchers.create(configuration, contextFactory)) {
            serverThread = new Thread("test-io-dispatcher") {

                @Override
                public void run() {
                    long smem = Unsafe.malloc(1, MemoryTag.NATIVE_DEFAULT);
                    try {
                        IORequestProcessor<IOContext> requestProcessor = (operation, context) -> {
                            long fd = context.getFd();
                            int rc;
                            switch(operation) {
                                case IOOperation.READ:
                                    rc = Net.recv(fd, smem, 1);
                                    if (rc == 1) {
                                        dispatcher.registerChannel(context, IOOperation.WRITE);
                                    } else {
                                        dispatcher.disconnect(context, IODispatcher.DISCONNECT_REASON_TEST);
                                    }
                                    break;
                                case IOOperation.WRITE:
                                    rc = Net.send(fd, smem, 1);
                                    if (rc == 1) {
                                        dispatcher.registerChannel(context, IOOperation.READ);
                                    } else {
                                        dispatcher.disconnect(context, IODispatcher.DISCONNECT_REASON_TEST);
                                    }
                                    break;
                                default:
                                    dispatcher.disconnect(context, IODispatcher.DISCONNECT_REASON_TEST);
                            }
                        };
                        do {
                            dispatcher.run(0);
                            dispatcher.processIOQueue(requestProcessor);
                            Thread.yield();
                        } while (!isInterrupted());
                    } finally {
                        Unsafe.free(smem, 1, MemoryTag.NATIVE_DEFAULT);
                        serverLatch.countDown();
                    }
                }
            };
            serverThread.setDaemon(true);
            serverThread.start();
            // Connect exactly the right amount of clients to fill the active connection and connection backlog, after the
            // queuedConnectionTimeoutInMs the connections in the backlog should get refused
            int nClientConnects = 0;
            int nClientConnectRefused = 0;
            for (int i = 0; i < listenBackLog + activeConnectionLimit; i++) {
                long fd = Net.socketTcp(true);
                Assert.assertTrue(fd > -1);
                clientActiveFds.add(fd);
                if (Net.connect(fd, sockAddr) != 0) {
                    nClientConnectRefused++;
                    continue;
                }
                int rc = Net.send(fd, mem, request.length());
                if (rc < 0) {
                    nClientConnectRefused++;
                    continue;
                }
                rc = Net.recv(fd, mem, request.length());
                if (rc < 0) {
                    nClientConnectRefused++;
                } else {
                    nClientConnects++;
                }
            }
            Assert.assertEquals(activeConnectionLimit, nClientConnects);
            Assert.assertEquals(listenBackLog, nClientConnectRefused);
            Assert.assertFalse(dispatcher.isListening());
            // Close all connections and wait for server to resume listening
            while (clientActiveFds.size() > 0) {
                long fd = clientActiveFds.get(0);
                clientActiveFds.remove(fd);
                Net.close(fd);
            }
            long timeoutMs = System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(1);
            while (!dispatcher.isListening()) {
                if (System.currentTimeMillis() > timeoutMs) {
                    Assert.fail("Timeout waiting for server to start listening again");
                }
            }
            // Try connections again to make sure server is listening
            nClientConnects = 0;
            nClientConnectRefused = 0;
            for (int i = 0; i < listenBackLog + activeConnectionLimit; i++) {
                long fd = Net.socketTcp(true);
                Assert.assertTrue(fd > -1);
                clientActiveFds.add(fd);
                if (Net.connect(fd, sockAddr) != 0) {
                    nClientConnectRefused++;
                    continue;
                }
                int rc = Net.send(fd, mem, request.length());
                if (rc < 0) {
                    nClientConnectRefused++;
                    continue;
                }
                rc = Net.recv(fd, mem, request.length());
                if (rc < 0) {
                    nClientConnectRefused++;
                } else {
                    nClientConnects++;
                }
            }
            Assert.assertEquals(activeConnectionLimit, nClientConnects);
            Assert.assertEquals(listenBackLog, nClientConnectRefused);
            Assert.assertFalse(dispatcher.isListening());
            // Close all remaining client connections
            for (int n = 0; n < clientActiveFds.size(); n++) {
                long fd = clientActiveFds.get(n);
                Net.close(fd);
            }
            serverThread.interrupt();
            if (!serverLatch.await(1, TimeUnit.MINUTES)) {
                Assert.fail("Timeout waiting for server to end");
            }
        } finally {
            Net.freeSockAddr(sockAddr);
            Unsafe.free(mem, request.length(), MemoryTag.NATIVE_DEFAULT);
        }
    });
}
Also used : IOOperation(io.questdb.network.IOOperation) DefaultIODispatcherConfiguration(io.questdb.network.DefaultIODispatcherConfiguration) Log(io.questdb.log.Log) WorkerPoolConfiguration(io.questdb.mp.WorkerPoolConfiguration) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) TestUtils.assertMemoryLeak(io.questdb.test.tools.TestUtils.assertMemoryLeak) WorkerPool(io.questdb.mp.WorkerPool) Timestamps(io.questdb.std.datetime.microtime.Timestamps) TestLatchedCounterFunctionFactory(io.questdb.griffin.engine.functions.test.TestLatchedCounterFunctionFactory) QueryCache(io.questdb.cutlass.http.processors.QueryCache) io.questdb.std(io.questdb.std) IODispatchers(io.questdb.network.IODispatchers) CyclicBarrier(java.util.concurrent.CyclicBarrier) SOCountDownLatch(io.questdb.mp.SOCountDownLatch) LockSupport(java.util.concurrent.locks.LockSupport) StaticContentProcessor(io.questdb.cutlass.http.processors.StaticContentProcessor) CountDownLatch(java.util.concurrent.CountDownLatch) Path(io.questdb.std.str.Path) io.questdb.cairo(io.questdb.cairo) AllowAllCairoSecurityContext(io.questdb.cairo.security.AllowAllCairoSecurityContext) IORequestProcessor(io.questdb.network.IORequestProcessor) NotNull(org.jetbrains.annotations.NotNull) JsonQueryProcessor(io.questdb.cutlass.http.processors.JsonQueryProcessor) TextImportProcessor(io.questdb.cutlass.http.processors.TextImportProcessor) IODispatcher(io.questdb.network.IODispatcher) AbstractCharSequence(io.questdb.std.str.AbstractCharSequence) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) MPSequence(io.questdb.mp.MPSequence) IOContextFactory(io.questdb.network.IOContextFactory) NetUtils(io.questdb.cutlass.NetUtils) SqlException(io.questdb.griffin.SqlException) SCSequence(io.questdb.mp.SCSequence) IOContext(io.questdb.network.IOContext) TestUtils(io.questdb.test.tools.TestUtils) SqlCompiler(io.questdb.griffin.SqlCompiler) LogFactory(io.questdb.log.LogFactory) Metrics(io.questdb.Metrics) HealthCheckProcessor(io.questdb.cutlass.http.processors.HealthCheckProcessor) NetworkFacadeImpl(io.questdb.network.NetworkFacadeImpl) SqlExecutionContextImpl(io.questdb.griffin.SqlExecutionContextImpl) NetworkFacade(io.questdb.network.NetworkFacade) RingQueue(io.questdb.mp.RingQueue) PeerDisconnectedException(io.questdb.network.PeerDisconnectedException) TimeUnit(java.util.concurrent.TimeUnit) SharedRandom(io.questdb.griffin.engine.functions.rnd.SharedRandom) AtomicLong(java.util.concurrent.atomic.AtomicLong) PeerIsSlowToReadException(io.questdb.network.PeerIsSlowToReadException) StringSink(io.questdb.std.str.StringSink) Net(io.questdb.network.Net) MillisecondClock(io.questdb.std.datetime.millitime.MillisecondClock) IODispatcherConfiguration(io.questdb.network.IODispatcherConfiguration) org.junit(org.junit) SqlExecutionContext(io.questdb.griffin.SqlExecutionContext) TemporaryFolder(org.junit.rules.TemporaryFolder) ByteSequence(io.questdb.std.str.ByteSequence) InputStream(java.io.InputStream) DefaultIODispatcherConfiguration(io.questdb.network.DefaultIODispatcherConfiguration) IODispatcherConfiguration(io.questdb.network.IODispatcherConfiguration) IODispatcher(io.questdb.network.IODispatcher) IORequestProcessor(io.questdb.network.IORequestProcessor) SOCountDownLatch(io.questdb.mp.SOCountDownLatch) CountDownLatch(java.util.concurrent.CountDownLatch) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) DefaultIODispatcherConfiguration(io.questdb.network.DefaultIODispatcherConfiguration) IOContext(io.questdb.network.IOContext)

Aggregations

SOCountDownLatch (io.questdb.mp.SOCountDownLatch)9 DefaultIODispatcherConfiguration (io.questdb.network.DefaultIODispatcherConfiguration)9 NetworkFacade (io.questdb.network.NetworkFacade)9 NetworkFacadeImpl (io.questdb.network.NetworkFacadeImpl)9 Metrics (io.questdb.Metrics)8 io.questdb.cairo (io.questdb.cairo)8 AllowAllCairoSecurityContext (io.questdb.cairo.security.AllowAllCairoSecurityContext)8 NetUtils (io.questdb.cutlass.NetUtils)8 HealthCheckProcessor (io.questdb.cutlass.http.processors.HealthCheckProcessor)8 JsonQueryProcessor (io.questdb.cutlass.http.processors.JsonQueryProcessor)8 QueryCache (io.questdb.cutlass.http.processors.QueryCache)8 StaticContentProcessor (io.questdb.cutlass.http.processors.StaticContentProcessor)8 TextImportProcessor (io.questdb.cutlass.http.processors.TextImportProcessor)8 SqlCompiler (io.questdb.griffin.SqlCompiler)8 SqlException (io.questdb.griffin.SqlException)8 SqlExecutionContext (io.questdb.griffin.SqlExecutionContext)8 SqlExecutionContextImpl (io.questdb.griffin.SqlExecutionContextImpl)8 SharedRandom (io.questdb.griffin.engine.functions.rnd.SharedRandom)8 TestLatchedCounterFunctionFactory (io.questdb.griffin.engine.functions.test.TestLatchedCounterFunctionFactory)8 Log (io.questdb.log.Log)8