From e2ee517fc9a2483c790127ef6f8d63d2bef84d5d Mon Sep 17 00:00:00 2001 From: Vlad Ilyushchenko Date: Fri, 10 May 2019 08:21:07 +0100 Subject: [PATCH] Misc: JMH benchmark for Log4j2 vs QuestDb Log. Good news QuestDb Log is 20x faster and absolutely zero GC NET: work in progress regarding text file upload, working to test slow/interrupted uploads Misc: added Os.currentTimeNanos() implementation only for linux for now, will add other OS soon Misc: commented out legacy test that is failing intermittently. I am rewriting this part of code completely and will focus on new code and tests working consistently --- benchmarks/pom.xml | 12 +- .../main/java/org/questdb/Log4jBenchmark.java | 63 +++++++ .../main/java/org/questdb/LogBenchmark.java | 72 ++++++++ benchmarks/src/main/resources/log4j2.xml | 39 ++++ core/CMakeLists.txt | 2 +- core/src/main/c/linux/clock.c | 35 ++++ .../cutlass/http/HttpConnectionContext.java | 21 +-- .../http/HttpMultipartContentListener.java | 4 +- .../http/HttpMultipartContentParser.java | 2 +- .../questdb/cutlass/http/HttpRawSocket.java | 2 +- .../cutlass/http/HttpRequestProcessor.java | 4 +- .../cutlass/http/HttpResponseHeader.java | 2 +- .../cutlass/http/HttpResponseSink.java | 26 +-- ...on.java => PeerIsSlowToReadException.java} | 4 +- .../processors/StaticContentProcessor.java | 12 +- .../http/processors/TextImportProcessor.java | 18 +- core/src/main/java/com/questdb/std/Os.java | 2 + .../resources/binaries/linux/libquestdb.so | Bin 138032 -> 138256 bytes .../cutlass/http/IODispatcherTest.java | 172 +++++++++++++++++- .../handlers/QueryHandlerSmallBufferTest.java | 3 +- 20 files changed, 443 insertions(+), 52 deletions(-) create mode 100644 benchmarks/src/main/java/org/questdb/Log4jBenchmark.java create mode 100644 benchmarks/src/main/java/org/questdb/LogBenchmark.java create mode 100644 benchmarks/src/main/resources/log4j2.xml create mode 100644 core/src/main/c/linux/clock.c rename core/src/main/java/com/questdb/cutlass/http/{PeerIsSlowException.java => PeerIsSlowToReadException.java} (86%) diff --git a/benchmarks/pom.xml b/benchmarks/pom.xml index ba376f92e..9d31500fc 100644 --- a/benchmarks/pom.xml +++ b/benchmarks/pom.xml @@ -54,6 +54,16 @@ questdb-core 3.1.1 + + org.apache.logging.log4j + log4j-core + 2.11.2 + + + com.lmax + disruptor + 3.3.4 + @@ -62,7 +72,7 @@ - 1.19 + 1.21 + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index caff34726..6fb69026d 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -41,7 +41,7 @@ elseif (UNIX) src/main/c/linux/recvmmsg.c src/main/c/linux/affinity.c src/main/c/linux/accept.c - ) + src/main/c/linux/clock.c) endif (APPLE) if (WIN32) diff --git a/core/src/main/c/linux/clock.c b/core/src/main/c/linux/clock.c new file mode 100644 index 000000000..6ca5ede7f --- /dev/null +++ b/core/src/main/c/linux/clock.c @@ -0,0 +1,35 @@ +/******************************************************************************* + * ___ _ ____ ____ + * / _ \ _ _ ___ ___| |_| _ \| __ ) + * | | | | | | |/ _ \/ __| __| | | | _ \ + * | |_| | |_| | __/\__ \ |_| |_| | |_) | + * \__\_\\__,_|\___||___/\__|____/|____/ + * + * Copyright (C) 2014-2019 Appsicle + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + ******************************************************************************/ + +#define _GNU_SOURCE + +#include +#include + +JNIEXPORT jlong JNICALL Java_com_questdb_std_Os_currentTimeNanos + (JNIEnv *e, jclass cl) { + + struct timespec timespec; + clock_gettime(CLOCK_REALTIME, ×pec); + return timespec.tv_sec * 100000000L + timespec.tv_nsec; +} diff --git a/core/src/main/java/com/questdb/cutlass/http/HttpConnectionContext.java b/core/src/main/java/com/questdb/cutlass/http/HttpConnectionContext.java index 5d2738939..ab4866eaf 100644 --- a/core/src/main/java/com/questdb/cutlass/http/HttpConnectionContext.java +++ b/core/src/main/java/com/questdb/cutlass/http/HttpConnectionContext.java @@ -43,9 +43,9 @@ public class HttpConnectionContext implements IOContext, Locality, Mutable { private final HttpServerConfiguration configuration; private final LocalValueMap localValueMap = new LocalValueMap(); private final NetworkFacade nf; + private final long multipartIdleSpinCount; private long fd; private HttpRequestProcessor resumeProcessor = null; - private final long multipartIdleSpinCount; public HttpConnectionContext(HttpServerConfiguration configuration) { this.configuration = configuration; @@ -126,7 +126,7 @@ public class HttpConnectionContext implements IOContext, Locality, Mutable { } catch (PeerDisconnectedException ignore) { LOG.debug().$("peer disconnected").$(); dispatcher.disconnect(this, DisconnectReason.PEER); - } catch (PeerIsSlowException ignore) { + } catch (PeerIsSlowToReadException ignore) { LOG.debug().$("peer is slow writer").$(); dispatcher.registerChannel(this, IOOperation.READ); } @@ -137,7 +137,7 @@ public class HttpConnectionContext implements IOContext, Locality, Mutable { responseSink.resumeSend(); resumeProcessor.resumeSend(this, dispatcher); resumeProcessor = null; - } catch (PeerIsSlowException ignore) { + } catch (PeerIsSlowToReadException ignore) { LOG.debug().$("peer is slow reader").$(); dispatcher.registerChannel(this, IOOperation.WRITE); } catch (PeerDisconnectedException ignore) { @@ -169,16 +169,15 @@ public class HttpConnectionContext implements IOContext, Locality, Mutable { processor.onRequestComplete(this, dispatcher); } catch (PeerDisconnectedException ignore) { dispatcher.disconnect(this, DisconnectReason.PEER); - } catch (PeerIsSlowException e) { - // todo: this has to be re-queued as WRITE - e.printStackTrace(); + } catch (PeerIsSlowToReadException e) { + dispatcher.registerChannel(this, IOOperation.WRITE); } } private void handleClientRecv( IODispatcher dispatcher, HttpRequestProcessorSelector selector - ) throws PeerDisconnectedException, PeerIsSlowException { + ) throws PeerDisconnectedException, PeerIsSlowToReadException { try { long fd = this.fd; // this is address of where header ended in our receive buffer @@ -201,6 +200,7 @@ public class HttpConnectionContext implements IOContext, Locality, Mutable { if (read == 0) { // client is not sending anything + LOG.info().$("ok, laters").$(); dispatcher.registerChannel(this, IOOperation.READ); return; } @@ -261,9 +261,6 @@ public class HttpConnectionContext implements IOContext, Locality, Mutable { while (true) { final int n = nf.recv(fd, buf, bufRemaining); - LOG.debug().$("multipart recv [len=").$(n) - .$(']').$(); - if (n < 0) { dispatcher.disconnect(this, DisconnectReason.PEER); break; @@ -299,6 +296,8 @@ public class HttpConnectionContext implements IOContext, Locality, Mutable { break; } + LOG.debug().$("multipart recv [len=").$(n).$(']').$(); + bufRemaining -= n; buf += n; @@ -331,7 +330,7 @@ public class HttpConnectionContext implements IOContext, Locality, Mutable { resumeProcessor = null; } catch (PeerDisconnectedException ignore) { dispatcher.disconnect(this, DisconnectReason.PEER); - } catch (PeerIsSlowException ignore) { + } catch (PeerIsSlowToReadException ignore) { LOG.debug().$("peer is slow reader [two]").$(); dispatcher.registerChannel(this, IOOperation.WRITE); resumeProcessor = processor; diff --git a/core/src/main/java/com/questdb/cutlass/http/HttpMultipartContentListener.java b/core/src/main/java/com/questdb/cutlass/http/HttpMultipartContentListener.java index a158f9afc..fd1b75bfc 100644 --- a/core/src/main/java/com/questdb/cutlass/http/HttpMultipartContentListener.java +++ b/core/src/main/java/com/questdb/cutlass/http/HttpMultipartContentListener.java @@ -26,7 +26,7 @@ package com.questdb.cutlass.http; public interface HttpMultipartContentListener { void onChunk(HttpRequestHeader partHeader, long lo, long hi); - void onPartBegin(HttpRequestHeader partHeader) throws PeerDisconnectedException, PeerIsSlowException; + void onPartBegin(HttpRequestHeader partHeader) throws PeerDisconnectedException, PeerIsSlowToReadException; - void onPartEnd(HttpRequestHeader partHeader) throws PeerDisconnectedException, PeerIsSlowException; + void onPartEnd(HttpRequestHeader partHeader) throws PeerDisconnectedException, PeerIsSlowToReadException; } diff --git a/core/src/main/java/com/questdb/cutlass/http/HttpMultipartContentParser.java b/core/src/main/java/com/questdb/cutlass/http/HttpMultipartContentParser.java index 5970f8bb9..846454b99 100644 --- a/core/src/main/java/com/questdb/cutlass/http/HttpMultipartContentParser.java +++ b/core/src/main/java/com/questdb/cutlass/http/HttpMultipartContentParser.java @@ -86,7 +86,7 @@ public class HttpMultipartContentParser implements Closeable, Mutable { return this; } - public boolean parse(long lo, long hi, HttpMultipartContentListener listener) throws PeerDisconnectedException, PeerIsSlowException { + public boolean parse(long lo, long hi, HttpMultipartContentListener listener) throws PeerDisconnectedException, PeerIsSlowToReadException { long _lo = Long.MAX_VALUE; long ptr = lo; while (ptr < hi) { diff --git a/core/src/main/java/com/questdb/cutlass/http/HttpRawSocket.java b/core/src/main/java/com/questdb/cutlass/http/HttpRawSocket.java index 07d7f0849..5e19c406e 100644 --- a/core/src/main/java/com/questdb/cutlass/http/HttpRawSocket.java +++ b/core/src/main/java/com/questdb/cutlass/http/HttpRawSocket.java @@ -28,5 +28,5 @@ public interface HttpRawSocket { int getBufferSize(); - void send(int size) throws PeerDisconnectedException, PeerIsSlowException; + void send(int size) throws PeerDisconnectedException, PeerIsSlowToReadException; } diff --git a/core/src/main/java/com/questdb/cutlass/http/HttpRequestProcessor.java b/core/src/main/java/com/questdb/cutlass/http/HttpRequestProcessor.java index 2dff9682e..69335608d 100644 --- a/core/src/main/java/com/questdb/cutlass/http/HttpRequestProcessor.java +++ b/core/src/main/java/com/questdb/cutlass/http/HttpRequestProcessor.java @@ -28,11 +28,11 @@ import com.questdb.network.IODispatcher; public interface HttpRequestProcessor { void onHeadersReady(HttpConnectionContext context); - void onRequestComplete(HttpConnectionContext context, IODispatcher dispatcher) throws PeerDisconnectedException, PeerIsSlowException; + void onRequestComplete(HttpConnectionContext context, IODispatcher dispatcher) throws PeerDisconnectedException, PeerIsSlowToReadException; default void resumeRecv(HttpConnectionContext context, IODispatcher dispatcher) { } - default void resumeSend(HttpConnectionContext context, IODispatcher dispatcher) throws PeerDisconnectedException, PeerIsSlowException { + default void resumeSend(HttpConnectionContext context, IODispatcher dispatcher) throws PeerDisconnectedException, PeerIsSlowToReadException { } } diff --git a/core/src/main/java/com/questdb/cutlass/http/HttpResponseHeader.java b/core/src/main/java/com/questdb/cutlass/http/HttpResponseHeader.java index 6d5dfdb38..3c0528ce4 100644 --- a/core/src/main/java/com/questdb/cutlass/http/HttpResponseHeader.java +++ b/core/src/main/java/com/questdb/cutlass/http/HttpResponseHeader.java @@ -26,7 +26,7 @@ package com.questdb.cutlass.http; import com.questdb.std.str.CharSink; public interface HttpResponseHeader extends CharSink { - void send() throws PeerDisconnectedException, PeerIsSlowException; + void send() throws PeerDisconnectedException, PeerIsSlowToReadException; String status(int code, CharSequence contentType, long contentLength); } diff --git a/core/src/main/java/com/questdb/cutlass/http/HttpResponseSink.java b/core/src/main/java/com/questdb/cutlass/http/HttpResponseSink.java index 9f1481a6e..144690581 100644 --- a/core/src/main/java/com/questdb/cutlass/http/HttpResponseSink.java +++ b/core/src/main/java/com/questdb/cutlass/http/HttpResponseSink.java @@ -125,7 +125,7 @@ public class HttpResponseSink implements Closeable, Mutable { return simple; } - public void resumeSend() throws PeerDisconnectedException, PeerIsSlowException { + public void resumeSend() throws PeerDisconnectedException, PeerIsSlowToReadException { while (true) { if (flushBufSize > 0) { @@ -244,7 +244,7 @@ public class HttpResponseSink implements Closeable, Mutable { return flush && ret == 1 ? SEND_DEFLATED_END : SEND_DEFLATED_CONT; } - private void flushSingle() throws PeerDisconnectedException, PeerIsSlowException { + private void flushSingle() throws PeerDisconnectedException, PeerIsSlowToReadException { state = DONE; send(); } @@ -300,12 +300,12 @@ public class HttpResponseSink implements Closeable, Mutable { this.total = 0; } - private void resumeSend(int nextState) throws PeerDisconnectedException, PeerIsSlowException { + private void resumeSend(int nextState) throws PeerDisconnectedException, PeerIsSlowToReadException { state = nextState; resumeSend(); } - private void send() throws PeerDisconnectedException, PeerIsSlowException { + private void send() throws PeerDisconnectedException, PeerIsSlowToReadException { int sent = 0; while (sent < flushBufSize) { int n = nf.send(fd, flushBuf + sent, flushBufSize - sent); @@ -318,7 +318,7 @@ public class HttpResponseSink implements Closeable, Mutable { // test how many times we tried to send before parking up flushBuf += sent; flushBufSize -= sent; - throw PeerIsSlowException.INSTANCE; + throw PeerIsSlowToReadException.INSTANCE; } else { sent += n; } @@ -380,7 +380,7 @@ public class HttpResponseSink implements Closeable, Mutable { } @Override - public void send() throws PeerDisconnectedException, PeerIsSlowException { + public void send() throws PeerDisconnectedException, PeerIsSlowToReadException { headerImpl.prepareToSend(); flushSingle(); } @@ -423,20 +423,20 @@ public class HttpResponseSink implements Closeable, Mutable { public class SimpleResponseImpl { - public void sendStatus(int code, CharSequence message) throws PeerDisconnectedException, PeerIsSlowException { + public void sendStatus(int code, CharSequence message) throws PeerDisconnectedException, PeerIsSlowToReadException { final String std = headerImpl.status(code, "text/html; charset=utf-8", -1L); sink.put(message == null ? std : message).put(Misc.EOL); prepareHeaderSink(); resumeSend(CHUNK_HEAD); } - public void sendStatus(int code) throws PeerDisconnectedException, PeerIsSlowException { + public void sendStatus(int code) throws PeerDisconnectedException, PeerIsSlowToReadException { headerImpl.status(code, "text/html; charset=utf-8", -2L); prepareHeaderSink(); flushSingle(); } - public void sendStatusWithDefaultMessage(int code) throws PeerDisconnectedException, PeerIsSlowException { + public void sendStatusWithDefaultMessage(int code) throws PeerDisconnectedException, PeerIsSlowToReadException { sendStatus(code, null); } } @@ -542,7 +542,7 @@ public class HttpResponseSink implements Closeable, Mutable { } @Override - public void send(int size) throws PeerDisconnectedException, PeerIsSlowException { + public void send(int size) throws PeerDisconnectedException, PeerIsSlowToReadException { flushBuf = out; flushBufSize = size; flushSingle(); @@ -557,7 +557,7 @@ public class HttpResponseSink implements Closeable, Mutable { bookmark = _wPtr; } - public void done() throws PeerDisconnectedException, PeerIsSlowException { + public void done() throws PeerDisconnectedException, PeerIsSlowToReadException { flushBufSize = 0; if (compressed) { resumeSend(FLUSH); @@ -580,7 +580,7 @@ public class HttpResponseSink implements Closeable, Mutable { return bookmark != outPtr; } - public void sendChunk() throws PeerDisconnectedException, PeerIsSlowException { + public void sendChunk() throws PeerDisconnectedException, PeerIsSlowToReadException { if (outPtr != _wPtr) { if (compressed) { flushBufSize = 0; @@ -592,7 +592,7 @@ public class HttpResponseSink implements Closeable, Mutable { } } - public void sendHeader() throws PeerDisconnectedException, PeerIsSlowException { + public void sendHeader() throws PeerDisconnectedException, PeerIsSlowToReadException { prepareHeaderSink(); flushSingle(); } diff --git a/core/src/main/java/com/questdb/cutlass/http/PeerIsSlowException.java b/core/src/main/java/com/questdb/cutlass/http/PeerIsSlowToReadException.java similarity index 86% rename from core/src/main/java/com/questdb/cutlass/http/PeerIsSlowException.java rename to core/src/main/java/com/questdb/cutlass/http/PeerIsSlowToReadException.java index 74be2d997..56941cbd4 100644 --- a/core/src/main/java/com/questdb/cutlass/http/PeerIsSlowException.java +++ b/core/src/main/java/com/questdb/cutlass/http/PeerIsSlowToReadException.java @@ -23,6 +23,6 @@ package com.questdb.cutlass.http; -public class PeerIsSlowException extends HttpFlowControlException { - public static final PeerIsSlowException INSTANCE = new PeerIsSlowException(); +public class PeerIsSlowToReadException extends HttpFlowControlException { + public static final PeerIsSlowToReadException INSTANCE = new PeerIsSlowToReadException(); } diff --git a/core/src/main/java/com/questdb/cutlass/http/processors/StaticContentProcessor.java b/core/src/main/java/com/questdb/cutlass/http/processors/StaticContentProcessor.java index 62599641d..90d10f2af 100644 --- a/core/src/main/java/com/questdb/cutlass/http/processors/StaticContentProcessor.java +++ b/core/src/main/java/com/questdb/cutlass/http/processors/StaticContentProcessor.java @@ -64,7 +64,7 @@ public class StaticContentProcessor implements HttpRequestProcessor, Closeable { public void onRequestComplete( HttpConnectionContext context, IODispatcher dispatcher - ) throws PeerDisconnectedException, PeerIsSlowException { + ) throws PeerDisconnectedException, PeerIsSlowToReadException { HttpRequestHeader headers = context.getRequestHeader(); CharSequence url = headers.getUrl(); LOG.info().$("incoming [url=").$(url).$(']').$(); @@ -92,7 +92,7 @@ public class StaticContentProcessor implements HttpRequestProcessor, Closeable { } @Override - public void resumeSend(HttpConnectionContext context, IODispatcher dispatcher) throws PeerDisconnectedException, PeerIsSlowException { + public void resumeSend(HttpConnectionContext context, IODispatcher dispatcher) throws PeerDisconnectedException, PeerIsSlowToReadException { LOG.debug().$("resumeSend").$(); StaticContentProcessorState state = stateAccessor.get(context); @@ -122,7 +122,7 @@ public class StaticContentProcessor implements HttpRequestProcessor, Closeable { dispatcher.registerChannel(context, IOOperation.READ); } - private void send(HttpConnectionContext context, IODispatcher dispatcher, LPSZ path, boolean asAttachment) throws PeerDisconnectedException, PeerIsSlowException { + private void send(HttpConnectionContext context, IODispatcher dispatcher, LPSZ path, boolean asAttachment) throws PeerDisconnectedException, PeerIsSlowToReadException { int n = Chars.lastIndexOf(path, '.'); if (n == -1) { LOG.info().$("Missing extension: ").$(path).$(); @@ -168,7 +168,7 @@ public class StaticContentProcessor implements HttpRequestProcessor, Closeable { CharSequence range, LPSZ path, CharSequence contentType, - boolean asAttachment) throws PeerDisconnectedException, PeerIsSlowException { + boolean asAttachment) throws PeerDisconnectedException, PeerIsSlowToReadException { if (rangeParser.of(range)) { StaticContentProcessorState state = stateAccessor.get(context); @@ -210,7 +210,7 @@ public class StaticContentProcessor implements HttpRequestProcessor, Closeable { } } - private void sendStatusWithDefaultMessage(HttpConnectionContext context, IODispatcher dispatcher, int code) throws PeerDisconnectedException, PeerIsSlowException { + private void sendStatusWithDefaultMessage(HttpConnectionContext context, IODispatcher dispatcher, int code) throws PeerDisconnectedException, PeerIsSlowToReadException { context.simpleResponse().sendStatusWithDefaultMessage(code); readyForNextRequest(context, dispatcher); } @@ -220,7 +220,7 @@ public class StaticContentProcessor implements HttpRequestProcessor, Closeable { IODispatcher dispatcher, LPSZ path, CharSequence contentType, boolean asAttachment - ) throws PeerDisconnectedException, PeerIsSlowException { + ) throws PeerDisconnectedException, PeerIsSlowToReadException { long fd = ff.openRO(path); if (fd == -1) { LOG.info().$("Cannot open file: ").$(path).$('(').$(ff.errno()).$(')').$(); diff --git a/core/src/main/java/com/questdb/cutlass/http/processors/TextImportProcessor.java b/core/src/main/java/com/questdb/cutlass/http/processors/TextImportProcessor.java index 79bf52078..1685ce5a9 100644 --- a/core/src/main/java/com/questdb/cutlass/http/processors/TextImportProcessor.java +++ b/core/src/main/java/com/questdb/cutlass/http/processors/TextImportProcessor.java @@ -94,7 +94,7 @@ public class TextImportProcessor implements HttpRequestProcessor, HttpMultipartC } @Override - public void onPartBegin(HttpRequestHeader partHeader) throws PeerDisconnectedException, PeerIsSlowException { + public void onPartBegin(HttpRequestHeader partHeader) throws PeerDisconnectedException, PeerIsSlowToReadException { LOG.debug().$("part begin [name=").$(partHeader.getContentDispositionName()).$(']').$(); if (Chars.equals("data", partHeader.getContentDispositionName())) { @@ -139,7 +139,7 @@ public class TextImportProcessor implements HttpRequestProcessor, HttpMultipartC // valid during multipart events. @Override - public void onPartEnd(HttpRequestHeader partHeader) throws PeerDisconnectedException, PeerIsSlowException { + public void onPartEnd(HttpRequestHeader partHeader) throws PeerDisconnectedException, PeerIsSlowToReadException { try { LOG.debug().$("part end").$(); transientState.textLoader.wrapUp(); @@ -180,11 +180,11 @@ public class TextImportProcessor implements HttpRequestProcessor, HttpMultipartC } @Override - public void resumeSend(HttpConnectionContext context, IODispatcher dispatcher) throws PeerDisconnectedException, PeerIsSlowException { + public void resumeSend(HttpConnectionContext context, IODispatcher dispatcher) throws PeerDisconnectedException, PeerIsSlowToReadException { doResumeSend(lvContext.get(context), context.getChunkedResponseSocket()); } - private static void resumeJson(TextImportProcessorState state, HttpResponseSink.ChunkedResponseImpl r) throws PeerDisconnectedException, PeerIsSlowException { + private static void resumeJson(TextImportProcessorState state, HttpResponseSink.ChunkedResponseImpl r) throws PeerDisconnectedException, PeerIsSlowToReadException { final TextLoader textLoader = state.textLoader; final RecordMetadata m = textLoader.getMetadata(); final int columnCount = m.getColumnCount(); @@ -279,7 +279,7 @@ public class TextImportProcessor implements HttpRequestProcessor, HttpMultipartC b.put("+\r\n"); } - private static void resumeText(TextImportProcessorState h, HttpResponseSink.ChunkedResponseImpl r) throws PeerDisconnectedException, PeerIsSlowException { + private static void resumeText(TextImportProcessorState h, HttpResponseSink.ChunkedResponseImpl r) throws PeerDisconnectedException, PeerIsSlowToReadException { final TextLoader textLoader = h.textLoader; final RecordMetadata metadata = textLoader.getMetadata(); LongList errors = textLoader.getColumnErrorCounts(); @@ -355,7 +355,7 @@ public class TextImportProcessor implements HttpRequestProcessor, HttpMultipartC return atomicity == -1 ? Atomicity.SKIP_COL : atomicity; } - private void doResumeSend(TextImportProcessorState state, HttpResponseSink.ChunkedResponseImpl response) throws PeerDisconnectedException, PeerIsSlowException { + private void doResumeSend(TextImportProcessorState state, HttpResponseSink.ChunkedResponseImpl response) throws PeerDisconnectedException, PeerIsSlowToReadException { try { if (state.json) { @@ -379,7 +379,7 @@ public class TextImportProcessor implements HttpRequestProcessor, HttpMultipartC state.clear(); } - private void handleJsonException(JsonException e) throws PeerDisconnectedException, PeerIsSlowException { + private void handleJsonException(JsonException e) throws PeerDisconnectedException, PeerIsSlowToReadException { if (configuration.abortBrokenUploads()) { sendError(transientContext, e.getMessage(), transientState.json); throw PeerDisconnectedException.INSTANCE; @@ -388,7 +388,7 @@ public class TextImportProcessor implements HttpRequestProcessor, HttpMultipartC transientState.stateMessage = e.getMessage(); } - private void sendError(HttpConnectionContext context, String message, boolean json) throws PeerDisconnectedException, PeerIsSlowException { + private void sendError(HttpConnectionContext context, String message, boolean json) throws PeerDisconnectedException, PeerIsSlowToReadException { HttpResponseSink.ChunkedResponseImpl sink = context.getChunkedResponseSocket(); if (json) { sink.status(200, CONTENT_TYPE_JSON); @@ -402,7 +402,7 @@ public class TextImportProcessor implements HttpRequestProcessor, HttpMultipartC throw PeerDisconnectedException.INSTANCE; } - private void sendResponse(HttpConnectionContext context) throws PeerDisconnectedException, PeerIsSlowException { + private void sendResponse(HttpConnectionContext context) throws PeerDisconnectedException, PeerIsSlowToReadException { TextImportProcessorState state = lvContext.get(context); // todo: may be set this up when headers are ready? state.json = Chars.equalsNc("json", context.getRequestHeader().getUrlParam("fmt")); diff --git a/core/src/main/java/com/questdb/std/Os.java b/core/src/main/java/com/questdb/std/Os.java index f080388c8..e16d86670 100644 --- a/core/src/main/java/com/questdb/std/Os.java +++ b/core/src/main/java/com/questdb/std/Os.java @@ -48,6 +48,8 @@ public final class Os { public static native long currentTimeMicros(); + public static native long currentTimeNanos(); + public static native int errno(); public static long forkExec(CharSequence args) { diff --git a/core/src/main/resources/binaries/linux/libquestdb.so b/core/src/main/resources/binaries/linux/libquestdb.so index 7e38968a51d30addf222871a4764357ac81e45e3..3313081644b87af6f36eeb0d67253b37eafb7b2a 100755 GIT binary patch delta 24219 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 fk@4hpPJ*d@WSd)3&E;Qq3hm diff --git a/core/src/test/java/com/questdb/cutlass/http/IODispatcherTest.java b/core/src/test/java/com/questdb/cutlass/http/IODispatcherTest.java index 5ef185470..80d630c33 100644 --- a/core/src/test/java/com/questdb/cutlass/http/IODispatcherTest.java +++ b/core/src/test/java/com/questdb/cutlass/http/IODispatcherTest.java @@ -49,6 +49,7 @@ import org.junit.Test; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.LockSupport; import static com.questdb.cutlass.http.HttpConnectionContext.dump; @@ -559,6 +560,175 @@ public class IODispatcherTest { }); } + @Test + @Ignore + public void testImportMultipleOnSameConnectionSlow() throws Exception { + TestUtils.assertMemoryLeak(() -> { + final String baseDir = System.getProperty("java.io.tmpdir"); + final DefaultHttpServerConfiguration httpConfiguration = createHttpServerConfiguration(baseDir); + + try (CairoEngine engine = new Engine(new DefaultCairoConfiguration(baseDir)); + HttpServer httpServer = new HttpServer(httpConfiguration)) { + httpServer.bind(new HttpRequestProcessorFactory() { + @Override + public String getUrl() { + return HttpServerConfiguration.DEFAULT_PROCESSOR_URL; + } + + @Override + public HttpRequestProcessor newInstance() { + return new StaticContentProcessor(httpConfiguration.getStaticContentProcessorConfiguration()); + } + }); + + httpServer.bind(new HttpRequestProcessorFactory() { + @Override + public String getUrl() { + return "/upload"; + } + + @Override + public HttpRequestProcessor newInstance() { + return new TextImportProcessor(httpConfiguration.getTextImportProcessorConfiguration(), engine); + } + }); + + httpServer.start(); + + // send multipart request to server + final String request = "POST /upload HTTP/1.1\r\n" + + "Host: localhost:9001\r\n" + + "User-Agent: curl/7.64.0\r\n" + + "Accept: */*\r\n" + + "Content-Length: 437760673\r\n" + + "Content-Type: multipart/form-data; boundary=------------------------27d997ca93d2689d\r\n" + + "Expect: 100-continue\r\n" + + "\r\n" + + "--------------------------27d997ca93d2689d\r\n" + + "Content-Disposition: form-data; name=\"schema\"; filename=\"schema.json\"\r\n" + + "Content-Type: application/octet-stream\r\n" + + "\r\n" + + "[\r\n" + + " {\r\n" + + " \"name\": \"date\",\r\n" + + " \"type\": \"DATE\",\r\n" + + " \"pattern\": \"d MMMM y.\",\r\n" + + " \"locale\": \"ru-RU\"\r\n" + + " }\r\n" + + "]\r\n" + + "\r\n" + + "--------------------------27d997ca93d2689d\r\n" + + "Content-Disposition: form-data; name=\"data\"; filename=\"fhv_tripdata_2017-02.csv\"\r\n" + + "Content-Type: application/octet-stream\r\n" + + "\r\n" + + "Dispatching_base_num,Pickup_DateTime,DropOff_datetime,PUlocationID,DOlocationID\r\n" + + "B00008,2017-02-01 00:30:00,,,\r\n" + + "B00008,2017-02-01 00:40:00,,,\r\n" + + "B00009,2017-02-01 00:30:00,,,\r\n" + + "B00013,2017-02-01 00:11:00,,,\r\n" + + "B00013,2017-02-01 00:41:00,,,\r\n" + + "B00013,2017-02-01 00:00:00,,,\r\n" + + "B00013,2017-02-01 00:53:00,,,\r\n" + + "B00013,2017-02-01 00:44:00,,,\r\n" + + "B00013,2017-02-01 00:05:00,,,\r\n" + + "B00013,2017-02-01 00:54:00,,,\r\n" + + "B00014,2017-02-01 00:45:00,,,\r\n" + + "B00014,2017-02-01 00:45:00,,,\r\n" + + "B00014,2017-02-01 00:46:00,,,\r\n" + + "B00014,2017-02-01 00:54:00,,,\r\n" + + "B00014,2017-02-01 00:45:00,,,\r\n" + + "B00014,2017-02-01 00:45:00,,,\r\n" + + "B00014,2017-02-01 00:45:00,,,\r\n" + + "B00014,2017-02-01 00:26:00,,,\r\n" + + "B00014,2017-02-01 00:55:00,,,\r\n" + + "B00014,2017-02-01 00:47:00,,,\r\n" + + "B00014,2017-02-01 00:05:00,,,\r\n" + + "B00014,2017-02-01 00:58:00,,,\r\n" + + "B00014,2017-02-01 00:33:00,,,\r\n" + + "B00014,2017-02-01 00:45:00,,,\r\n" + + "\r\n" + + "--------------------------27d997ca93d2689d--"; + + byte[] 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" + + "442\r\n" + + "+---------------------------------------------------------------------------------------------------------------+\r\n" + + "| Location: | fhv_tripdata_2017-02.csv | Pattern | Locale | Errors |\r\n" + + "| Partition by | NONE | | | |\r\n" + + "+---------------------------------------------------------------------------------------------------------------+\r\n" + + "| Rows handled | 24 | | | |\r\n" + + "| Rows imported | 24 | | | |\r\n" + + "+---------------------------------------------------------------------------------------------------------------+\r\n" + + "| 0 | 0 |\r\n" + + "| 1 | 0 |\r\n" + + "| 2 | 0 |\r\n" + + "| 3 | 0 |\r\n" + + "| 4 | 0 |\r\n" + + "+---------------------------------------------------------------------------------------------------------------+\r\n" + + "\r\n" + + "0\r\n" + + "\r\n").getBytes(); + + + long fd = Net.socketTcp(true); + try { + long sockAddr = Net.sockaddr("127.0.0.1", 9001); + try { + Assert.assertTrue(fd > -1); + Assert.assertEquals(0, Net.connect(fd, sockAddr)); + Net.setTcpNoDelay(fd, true); + + final int len = request.length(); + long ptr = Unsafe.malloc(((CharSequence) request).length()); + try { + for (int j = 0; j < 5; j++) { + System.out.println(j); + int sent = 0; + Chars.strcpy(request, ((CharSequence) request).length(), ptr); + while (sent < len) { + int n = Net.send(fd, ptr + sent, 1); + Assert.assertTrue(n > -1); + sent += n; + if (sent > 800) { + LockSupport.parkNanos(1_000_000); + } + } + + // receive response + final int expectedToReceive = expectedResponse.length; + int received = 0; + while (received < expectedToReceive) { + int n = Net.recv(fd, ptr + received, len - received); + // compare bytes + for (int i = 0; i < n; i++) { + if (expectedResponse[received + i] != Unsafe.getUnsafe().getByte(ptr + received + i)) { + dump(ptr, received + n); + Assert.fail("Error at: " + (received + i) + ", local=" + i); + } + } + + received += n; + } + } + } finally { + Unsafe.free(ptr, len); + } + } finally { + Net.freeSockAddr(sockAddr); + } + } finally { + Net.close(fd); + } + + httpServer.halt(); + } + }); + } + @Test public void testMaxConnections() throws Exception { @@ -1233,7 +1403,7 @@ public class IODispatcherTest { } @Override - public void onRequestComplete(HttpConnectionContext context, IODispatcher dispatcher1) throws PeerDisconnectedException, PeerIsSlowException { + public void onRequestComplete(HttpConnectionContext context, IODispatcher dispatcher1) throws PeerDisconnectedException, PeerIsSlowToReadException { context.simpleResponse().sendStatusWithDefaultMessage(200); dispatcher1.registerChannel(context, IOOperation.READ); } diff --git a/core/src/test/java/com/questdb/net/http/handlers/QueryHandlerSmallBufferTest.java b/core/src/test/java/com/questdb/net/http/handlers/QueryHandlerSmallBufferTest.java index bb6781cb2..b91d6ba77 100644 --- a/core/src/test/java/com/questdb/net/http/handlers/QueryHandlerSmallBufferTest.java +++ b/core/src/test/java/com/questdb/net/http/handlers/QueryHandlerSmallBufferTest.java @@ -5,7 +5,7 @@ * | |_| | |_| | __/\__ \ |_| |_| | |_) | * \__\_\\__,_|\___||___/\__|____/|____/ * - * Copyright (C) 2014-2018 Appsicle + * Copyright (C) 2014-2019 Appsicle * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, @@ -36,6 +36,7 @@ import org.junit.rules.TemporaryFolder; import java.sql.Timestamp; +@Ignore public class QueryHandlerSmallBufferTest extends AbstractOptimiserTest { @ClassRule -- GitLab