diff --git a/src/main/java/ru/vk/itmo/test/viktorkorotkikh/LSMServerImpl.java b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/LSMServerImpl.java index b5e3c72b3..fcbe7b035 100644 --- a/src/main/java/ru/vk/itmo/test/viktorkorotkikh/LSMServerImpl.java +++ b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/LSMServerImpl.java @@ -18,11 +18,12 @@ import ru.vk.itmo.test.viktorkorotkikh.dao.exceptions.LSMDaoOutOfMemoryException; import ru.vk.itmo.test.viktorkorotkikh.dao.exceptions.TooManyFlushesException; import ru.vk.itmo.test.viktorkorotkikh.http.LSMCustomSession; +import ru.vk.itmo.test.viktorkorotkikh.http.LSMRangeWriter; import ru.vk.itmo.test.viktorkorotkikh.http.LSMServerResponseWithMemorySegment; +import ru.vk.itmo.test.viktorkorotkikh.util.ClusterResponseMerger; import ru.vk.itmo.test.viktorkorotkikh.util.HttpResponseNodeResponse; import ru.vk.itmo.test.viktorkorotkikh.util.LSMConstantResponse; import ru.vk.itmo.test.viktorkorotkikh.util.LsmServerUtil; -import ru.vk.itmo.test.viktorkorotkikh.util.NodeResponse; import ru.vk.itmo.test.viktorkorotkikh.util.OneNioNodeResponse; import ru.vk.itmo.test.viktorkorotkikh.util.ReplicaEmptyResponse; import ru.vk.itmo.test.viktorkorotkikh.util.RequestParameters; @@ -35,18 +36,14 @@ import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.nio.charset.StandardCharsets; +import java.time.Duration; import java.time.Instant; -import java.util.ArrayList; import java.util.Iterator; -import java.util.List; import java.util.Map; import java.util.SequencedSet; import java.util.Set; -import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.RejectedExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; import static java.net.HttpURLConnection.HTTP_GATEWAY_TIMEOUT; import static java.net.HttpURLConnection.HTTP_UNAVAILABLE; @@ -66,13 +63,17 @@ public class LSMServerImpl extends HttpServer { private final String selfUrl; private final HttpClient clusterClient; private final ServiceConfig serviceConfig; + private final ExecutorService clusterResponseProcessor; + private final ExecutorService localProcessor; public LSMServerImpl( ServiceConfig serviceConfig, Dao> dao, ExecutorService executorService, ConsistentHashingManager consistentHashingManager, - HttpClient clusterClient + HttpClient clusterClient, + ExecutorService clusterResponseProcessor, + ExecutorService localProcessor ) throws IOException { super(createServerConfig(serviceConfig)); this.dao = dao; @@ -81,6 +82,8 @@ public LSMServerImpl( this.selfUrl = serviceConfig.selfUrl(); this.clusterClient = clusterClient; this.serviceConfig = serviceConfig; + this.clusterResponseProcessor = clusterResponseProcessor; + this.localProcessor = localProcessor; } private static HttpServerConfig createServerConfig(ServiceConfig serviceConfig) { @@ -103,6 +106,12 @@ public void handleRequest(Request request, HttpSession session) throws IOExcepti executorService.execute(() -> { try { final String path = request.getPath(); + + if (path.startsWith("/v0/entities") && request.getMethod() == METHOD_GET) { + handleEntitiesRangeRequest(request, (LSMCustomSession) session); + return; + } + if (path.startsWith("/v0/entity")) { handleEntityRequest(request, session); } else { @@ -186,15 +195,15 @@ public void handleEntityRequest(Request request, HttpSession session) throws IOE final SequencedSet replicas = consistentHashingManager.getReplicasSet(from, key); - final Response response = getResponseFromReplicas( + getResponseFromReplicas( request, from, replicas, key, id, - ack + ack, + session ); - session.sendResponse(response); } private static RequestParameters getRequestParameters(Request request) { @@ -220,34 +229,38 @@ private static RequestParameters getRequestParameters(Request request) { return new RequestParameters(id, ack, from); } - private Response getResponseFromReplicas( + private void getResponseFromReplicas( Request request, - Integer from, + int from, SequencedSet replicas, byte[] key, String id, - Integer ack + int ack, + HttpSession session ) { - final List responses = new ArrayList<>(from); + final ClusterResponseMerger clusterResponseMerger = new ClusterResponseMerger(ack, from, request, session); final long requestTimestamp = Instant.now().toEpochMilli(); + int i = 0; for (final String replicaUrl : replicas) { if (replicaUrl.equals(selfUrl)) { - responses.add(processLocal(request, key, id, requestTimestamp)); + processLocalAsync(request, key, id, requestTimestamp, i, clusterResponseMerger); } else { - responses.add(processRemote(request, replicaUrl, id, requestTimestamp)); + processRemote(request, replicaUrl, id, requestTimestamp, i, clusterResponseMerger); } + i++; } - return LsmServerUtil.mergeReplicasResponses(request, responses, ack); } - private NodeResponse processRemote( + private void processRemote( final Request originalRequest, final String server, final String id, - long requestTimestamp + long requestTimestamp, + int index, + ClusterResponseMerger clusterResponseMerge ) { final HttpRequest request = createClusterRequest(originalRequest, server, id, requestTimestamp); - return sendClusterRequest(request); + sendClusterRequest(request, index, clusterResponseMerge); } private static HttpRequest createClusterRequest( @@ -259,7 +272,8 @@ private static HttpRequest createClusterRequest( HttpRequest.Builder builder = HttpRequest.newBuilder() .uri(URI.create(server + ENTITY_V0_PATH_WITH_ID_PARAM + id)) .header(REPLICA_REQUEST_HEADER, "") - .header(LsmServerUtil.TIMESTAMP_HEADER, String.valueOf(requestTimestamp)); + .header(LsmServerUtil.TIMESTAMP_HEADER, String.valueOf(requestTimestamp)) + .timeout(Duration.ofMillis(CLUSTER_REQUEST_TIMEOUT_MILLISECONDS)); switch (originalRequest.getMethod()) { case METHOD_GET -> builder.GET(); case METHOD_PUT -> { @@ -275,29 +289,47 @@ private static HttpRequest createClusterRequest( return builder.build(); } - private NodeResponse sendClusterRequest( - final HttpRequest request + private void sendClusterRequest( + final HttpRequest request, + final int index, + final ClusterResponseMerger clusterResponseMerger ) { - try { - return new HttpResponseNodeResponse( - clusterClient - .sendAsync(request, HttpResponse.BodyHandlers.ofByteArray()) - .get(CLUSTER_REQUEST_TIMEOUT_MILLISECONDS, TimeUnit.MILLISECONDS) - ); - } catch (InterruptedException e) { - final String clusterUrl = request.uri().toString(); - Thread.currentThread().interrupt(); - log.warn("Current thread was interrupted during processing request to cluster {}", clusterUrl); - return new ReplicaEmptyResponse(HTTP_UNAVAILABLE); - } catch (ExecutionException e) { - final String clusterUrl = request.uri().toString(); - log.error("Unexpected exception occurred while sending request to cluster {}", clusterUrl, e); - return new ReplicaEmptyResponse(HTTP_UNAVAILABLE); - } catch (TimeoutException e) { - final String clusterUrl = request.uri().toString(); - log.warn("Request timeout to cluster server {}", clusterUrl); - return new ReplicaEmptyResponse(HTTP_GATEWAY_TIMEOUT); - } + clusterClient + .sendAsync(request, HttpResponse.BodyHandlers.ofByteArray()) + .thenAcceptAsync(response -> + clusterResponseMerger.addToMerge( + index, + new HttpResponseNodeResponse(response) + ), clusterResponseProcessor) + .exceptionallyAsync(throwable -> { + if (throwable.getCause() instanceof java.net.http.HttpTimeoutException) { + final String clusterUrl = request.uri().toString(); + log.warn("Request timeout to cluster server {}", clusterUrl); + clusterResponseMerger.addToMerge(index, new ReplicaEmptyResponse(HTTP_GATEWAY_TIMEOUT)); + } else { + final String clusterUrl = request.uri().toString(); + log.error( + "Unexpected exception occurred while sending request to cluster {}", + clusterUrl, + throwable + ); + clusterResponseMerger.addToMerge(index, new ReplicaEmptyResponse(HTTP_UNAVAILABLE)); + } + return null; + }, clusterResponseProcessor).state(); + } + + private void processLocalAsync( + Request request, + byte[] key, + String id, + long requestTimestamp, + int i, + ClusterResponseMerger clusterResponseMerger + ) { + localProcessor.execute(() -> + clusterResponseMerger.addToMerge(i, processLocal(request, key, id, requestTimestamp)) + ); } private OneNioNodeResponse processLocal( @@ -406,6 +438,21 @@ public Response handleCompact(Request request) throws IOException { return LSMConstantResponse.ok(request); } + public void handleEntitiesRangeRequest(Request request, LSMCustomSession session) throws IOException { + final String start = request.getParameter("start="); + final String end = request.getParameter("end="); + if (start == null || start.isEmpty() || (end != null && end.isEmpty())) { + log.debug("Bad request: start parameter and end parameter (if it present) should not be empty"); + session.sendResponse(LSMConstantResponse.badRequest(request)); + return; + } + + final MemorySegment startMemorySegment = fromByteArray(start.getBytes(StandardCharsets.UTF_8)); + final MemorySegment endMemorySegment = end == null ? null : fromByteArray(end.getBytes(StandardCharsets.UTF_8)); + Iterator> iterator = dao.get(startMemorySegment, endMemorySegment); + session.sendRangeResponse(new LSMRangeWriter(iterator, LSMConstantResponse.keepAlive(request))); + } + private static MemorySegment fromByteArray(final byte[] data) { return MemorySegment.ofArray(data); } diff --git a/src/main/java/ru/vk/itmo/test/viktorkorotkikh/LSMServiceImpl.java b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/LSMServiceImpl.java index 51794a728..f84e566d2 100644 --- a/src/main/java/ru/vk/itmo/test/viktorkorotkikh/LSMServiceImpl.java +++ b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/LSMServiceImpl.java @@ -30,6 +30,14 @@ public class LSMServiceImpl implements Service { private static final long FLUSH_THRESHOLD = 1 << 20; // 1 MB private static final int TERMINATION_TIMEOUT_SECONDS = 20; + private static final int SERVER_EXECUTOR_SERVICE_THREADS_COUNT = 16; + private static final int SERVER_EXECUTOR_SERVICE_QUEUE_SIZE = 1024; + private static final int CLUSTER_HTTP_CLIENT_EXECUTOR_SERVICE_THREADS_COUNT = 16; + private static final int CLUSTER_HTTP_CLIENT_EXECUTOR_SERVICE_QUEUE_SIZE = 1024; + private static final int CLUSTER_RESPONSE_EXECUTOR_SERVICE_THREADS_COUNT = 16; + private static final int CLUSTER_RESPONSE_EXECUTOR_SERVICE_QUEUE_SIZE = 1024; + private static final int LOCAL_REQUEST_EXECUTOR_SERVICE_THREADS_COUNT = 16; + private static final int LOCAL_REQUEST_EXECUTOR_SERVICE_QUEUE_SIZE = 1024; private final ServiceConfig serviceConfig; private LSMServerImpl httpServer; private boolean isRunning; @@ -38,6 +46,8 @@ public class LSMServiceImpl implements Service { private final ConsistentHashingManager consistentHashingManager; private HttpClient clusterClient; private ExecutorService clusterClientExecutorService; + private ExecutorService clusterResponseProcessor; + private ExecutorService localProcessor; public static void main(String[] args) throws IOException, ExecutionException, InterruptedException { Path baseWorkingDir = Path.of("daoWorkingDir"); @@ -96,14 +106,43 @@ public LSMServiceImpl(ServiceConfig serviceConfig) { this.consistentHashingManager = new ConsistentHashingManager(10, serviceConfig.clusterUrls()); } - private static LSMServerImpl createServer( - ServiceConfig serviceConfig, - Dao> dao, - ExecutorService executorService, - ConsistentHashingManager consistentHashingManager, - HttpClient clusterClient + private LSMServerImpl createServer( + Dao> dao ) throws IOException { - return new LSMServerImpl(serviceConfig, dao, executorService, consistentHashingManager, clusterClient); + executorService = createExecutorService( + SERVER_EXECUTOR_SERVICE_THREADS_COUNT, + SERVER_EXECUTOR_SERVICE_QUEUE_SIZE, + "worker" + ); + clusterClientExecutorService = createExecutorService( + CLUSTER_HTTP_CLIENT_EXECUTOR_SERVICE_THREADS_COUNT, + CLUSTER_HTTP_CLIENT_EXECUTOR_SERVICE_QUEUE_SIZE, + "cluster-request" + ); + clusterResponseProcessor = createExecutorService( + CLUSTER_RESPONSE_EXECUTOR_SERVICE_THREADS_COUNT, + CLUSTER_RESPONSE_EXECUTOR_SERVICE_QUEUE_SIZE, + "cluster-response-processor" + ); + localProcessor = createExecutorService( + LOCAL_REQUEST_EXECUTOR_SERVICE_THREADS_COUNT, + LOCAL_REQUEST_EXECUTOR_SERVICE_QUEUE_SIZE, + "local-processor" + ); + + clusterClient = HttpClient.newBuilder() + .executor(clusterClientExecutorService) + .build(); + + return new LSMServerImpl( + serviceConfig, + dao, + executorService, + consistentHashingManager, + clusterClient, + clusterResponseProcessor, + localProcessor + ); } private static Dao> createLSMDao(Path workingDir) { @@ -146,14 +185,7 @@ public synchronized CompletableFuture start() throws IOException { if (isRunning) return CompletableFuture.completedFuture(null); dao = createLSMDao(serviceConfig.workingDir()); - executorService = createExecutorService(16, 1024, "worker"); - clusterClientExecutorService = createExecutorService(16, 1024, "cluster-worker"); - - clusterClient = HttpClient.newBuilder() - .executor(clusterClientExecutorService) - .build(); - - httpServer = createServer(serviceConfig, dao, executorService, consistentHashingManager, clusterClient); + httpServer = createServer(dao); httpServer.start(); isRunning = true; @@ -167,6 +199,8 @@ public synchronized CompletableFuture stop() throws IOException { shutdownHttpClient(clusterClient); shutdownExecutorService(clusterClientExecutorService); + shutdownExecutorService(clusterResponseProcessor); + shutdownExecutorService(localProcessor); shutdownExecutorService(executorService); executorService = null; clusterClient = null; @@ -211,7 +245,7 @@ private static void shutdownHttpClient(HttpClient httpClient) { } } - @ServiceFactory(stage = 4) + @ServiceFactory(stage = 6) public static class LSMServiceFactoryImpl implements ServiceFactory.Factory { @Override public Service create(ServiceConfig config) { diff --git a/src/main/java/ru/vk/itmo/test/viktorkorotkikh/dao/MemTable.java b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/dao/MemTable.java index 1d606f38a..c227375f6 100644 --- a/src/main/java/ru/vk/itmo/test/viktorkorotkikh/dao/MemTable.java +++ b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/dao/MemTable.java @@ -4,6 +4,7 @@ import java.lang.foreign.MemorySegment; import java.util.Collection; +import java.util.Collections; import java.util.Iterator; import java.util.NavigableMap; import java.util.NoSuchElementException; @@ -39,7 +40,12 @@ private Iterator> storageIterator(MemorySegment return storage.tailMap(from).sequencedValues().iterator(); } - return storage.subMap(from, to).sequencedValues().iterator(); + try { + return storage.subMap(from, to).sequencedValues().iterator(); + } catch (IllegalArgumentException illegalArgumentException) { + // we get inconsistent range error when from > to + return Collections.emptyIterator(); + } } public MemTableIterator iterator(MemorySegment from, MemorySegment to, int priorityReduction) { diff --git a/src/main/java/ru/vk/itmo/test/viktorkorotkikh/http/Chunk.java b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/http/Chunk.java new file mode 100644 index 000000000..10fa2108f --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/http/Chunk.java @@ -0,0 +1,27 @@ +package ru.vk.itmo.test.viktorkorotkikh.http; + +import one.nio.util.ByteArrayBuilder; + +public class Chunk { + private final ByteArrayBuilder byteArrayBuilder; + private final int offset; + private final int length; + + public Chunk(ByteArrayBuilder buffer, int offset) { + this.byteArrayBuilder = buffer; + this.offset = offset; + this.length = buffer.length() - offset; + } + + public byte[] getBytes() { + return byteArrayBuilder.buffer(); + } + + public int offset() { + return offset; + } + + public int length() { + return length; + } +} diff --git a/src/main/java/ru/vk/itmo/test/viktorkorotkikh/http/LSMCustomSession.java b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/http/LSMCustomSession.java index 7cb755352..dd616a890 100644 --- a/src/main/java/ru/vk/itmo/test/viktorkorotkikh/http/LSMCustomSession.java +++ b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/http/LSMCustomSession.java @@ -10,6 +10,8 @@ import java.io.IOException; public class LSMCustomSession extends HttpSession { + private LSMRangeWriter lsmRangeWriter; + public LSMCustomSession(Socket socket, HttpServer server) { super(socket, server); } @@ -39,4 +41,40 @@ public synchronized void sendResponse(Response response) throws IOException { } } } + + @Override + protected void processWrite() throws Exception { + super.processWrite(); + sendNextRangeChunks(); + } + + public void sendRangeResponse(LSMRangeWriter lsmRangeWriter) throws IOException { + Request handling = this.handling; + if (handling == null) { + throw new IOException("Out of order response"); + } + server.incRequestsProcessed(); + + this.lsmRangeWriter = lsmRangeWriter; + sendNextRangeChunks(); + } + + private void sendNextRangeChunks() throws IOException { + if (lsmRangeWriter == null) return; + while (queueHead == null && lsmRangeWriter.hasChunks()) { + Chunk chunk = lsmRangeWriter.nextChunk(); + write(chunk.getBytes(), chunk.offset(), chunk.length()); + } + + if (!lsmRangeWriter.hasChunks()) { + this.handling = pipeline.pollFirst(); + if (handling != null) { + if (handling == FIN) { + scheduleClose(); + } else { + server.handleRequest(handling, this); + } + } + } + } } diff --git a/src/main/java/ru/vk/itmo/test/viktorkorotkikh/http/LSMRangeWriter.java b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/http/LSMRangeWriter.java new file mode 100644 index 000000000..67ec9ef76 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/http/LSMRangeWriter.java @@ -0,0 +1,168 @@ +package ru.vk.itmo.test.viktorkorotkikh.http; + +import one.nio.util.ByteArrayBuilder; +import one.nio.util.Utf8; +import ru.vk.itmo.test.viktorkorotkikh.dao.TimestampedEntry; +import ru.vk.itmo.test.viktorkorotkikh.util.LsmServerUtil; + +import java.lang.foreign.MemorySegment; +import java.util.Iterator; + +import static ru.vk.itmo.test.viktorkorotkikh.util.LSMConstantResponse.CHUNKED_RESPONSE_CLOSE_WITH_HEADERS_BYTES; +import static ru.vk.itmo.test.viktorkorotkikh.util.LSMConstantResponse.CHUNKED_RESPONSE_KEEP_ALIVE_WITH_HEADERS_BYTES; + +public class LSMRangeWriter { + private static final int BUFFER_SIZE = 8192; + private static final int CHUNK_SIZE_BYTES = 16; // long 8 bytes in hex + private static final byte[] CRLF_BYTES = new byte[]{'\r', '\n'}; + private final Iterator> entryIterator; + private final boolean keepAlive; + private final ByteArrayBuilder buffer; + private long chunkSize = 0; + private TimestampedEntry lastEntry; + private int lastEntryOffset; + private NextOperation nextOperation = NextOperation.WRITE_HEADERS; + + public LSMRangeWriter(Iterator> entryIterator, boolean keepAlive) { + this.entryIterator = entryIterator; + this.keepAlive = keepAlive; + this.buffer = new ByteArrayBuilder(BUFFER_SIZE); + } + + public boolean hasChunks() { + return entryIterator.hasNext() || nextOperation != null; + } + + public Chunk nextChunk() { + chunkSize = 0; + int chunkHeaderOffset = CHUNK_SIZE_BYTES + CRLF_BYTES.length; + boolean writeHttpHeaders = false; + if (nextOperation == NextOperation.WRITE_HEADERS) { + chunkHeaderOffset += keepAlive + ? CHUNKED_RESPONSE_KEEP_ALIVE_WITH_HEADERS_BYTES.length + : CHUNKED_RESPONSE_CLOSE_WITH_HEADERS_BYTES.length; + writeHttpHeaders = true; + } + buffer.setLength(chunkHeaderOffset); + + if (!appendNextOperationBytes()) { + int chunkOffset = writeChunkHeader(chunkHeaderOffset, writeHttpHeaders); + return new Chunk(buffer, chunkOffset); + } + + while (entryIterator.hasNext()) { + lastEntry = entryIterator.next(); + lastEntryOffset = 0; + + nextOperation = NextOperation.WRITE_KEY; + if (!appendNextOperationBytes()) { + int chunkOffset = writeChunkHeader(chunkHeaderOffset, writeHttpHeaders); + return new Chunk(buffer, chunkOffset); + } + } + + int chunkOffset = writeChunkHeader(chunkHeaderOffset, writeHttpHeaders); + if (chunkSize == 0) { + appendCLRF(buffer); + } else { + buffer.append(Long.toHexString(0)); + appendCLRF(buffer); + appendCLRF(buffer); + } + + nextOperation = null; + + return new Chunk(buffer, chunkOffset); + } + + private int writeChunkHeader(int chunkSizeOffset, boolean writeHttpHeaders) { + String chunkSizeHexString = Long.toHexString(chunkSize); + int chunkSizeHexStringLength = Utf8.length(chunkSizeHexString); + int chunkSizeStart = chunkSizeOffset - chunkSizeHexStringLength - CRLF_BYTES.length; + Utf8.write(chunkSizeHexString, buffer.buffer(), chunkSizeStart); + + System.arraycopy( + CRLF_BYTES, + 0, + buffer.buffer(), + chunkSizeStart + chunkSizeHexStringLength, + CRLF_BYTES.length + ); + + int headersOffset = 0; + if (writeHttpHeaders) { + byte[] headers = keepAlive + ? CHUNKED_RESPONSE_KEEP_ALIVE_WITH_HEADERS_BYTES + : CHUNKED_RESPONSE_CLOSE_WITH_HEADERS_BYTES; + System.arraycopy(headers, 0, buffer.buffer(), chunkSizeStart - headers.length, headers.length); + headersOffset = headers.length; + } + appendCLRF(buffer); + return chunkSizeStart - headersOffset; + } + + private boolean appendNextOperationBytes() { + return switch (nextOperation) { + case WRITE_HEADERS -> true; // we write headers later in writeChunkSize method + case WRITE_KEY -> { + if (buffer.length() + CRLF_BYTES.length >= buffer.capacity()) { + yield false; + } + + if (appendMemorySegment(lastEntry.key(), lastEntryOffset, true)) { + nextOperation = NextOperation.WRITE_DELIMITERS_AFTER_KEY; + yield appendNextOperationBytes(); + } + yield false; + } + case WRITE_DELIMITERS_AFTER_KEY -> { + if (buffer.length() + 1 + CRLF_BYTES.length <= buffer.capacity()) { + chunkSize += 1; + buffer.append('\n'); + nextOperation = NextOperation.WRITE_VALUE; + yield appendNextOperationBytes(); + } + yield false; + } + case WRITE_VALUE -> { + if (buffer.length() + CRLF_BYTES.length >= buffer.capacity()) { + yield false; + } + if (appendMemorySegment(lastEntry.value(), lastEntryOffset, false)) { + nextOperation = null; + yield true; + } + yield false; + } + case null -> true; + }; + } + + private boolean appendMemorySegment(MemorySegment memorySegment, int memorySegmentOffset, boolean isKey) { + int writtenMemorySegment = LsmServerUtil.copyMemorySegmentToByteArrayBuilder( + memorySegment, + memorySegmentOffset, + buffer, + buffer.capacity() - CRLF_BYTES.length + ); + chunkSize += writtenMemorySegment; + + if (lastEntryOffset + writtenMemorySegment < memorySegment.byteSize()) { + nextOperation = isKey ? NextOperation.WRITE_KEY : NextOperation.WRITE_VALUE; + lastEntryOffset += writtenMemorySegment; + return false; + } + lastEntryOffset = 0; + return true; + } + + private static void appendCLRF(final ByteArrayBuilder builder) { + builder.append(CRLF_BYTES); + } + + private enum NextOperation { + WRITE_HEADERS, + WRITE_KEY, WRITE_DELIMITERS_AFTER_KEY, + WRITE_VALUE + } +} diff --git a/src/main/java/ru/vk/itmo/test/viktorkorotkikh/http/LSMServerResponseWithMemorySegment.java b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/http/LSMServerResponseWithMemorySegment.java index ddfc00463..408f2437f 100644 --- a/src/main/java/ru/vk/itmo/test/viktorkorotkikh/http/LSMServerResponseWithMemorySegment.java +++ b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/http/LSMServerResponseWithMemorySegment.java @@ -3,6 +3,7 @@ import one.nio.http.Response; import one.nio.util.ByteArrayBuilder; import one.nio.util.Utf8; +import ru.vk.itmo.test.viktorkorotkikh.util.LsmServerUtil; import java.lang.foreign.MemorySegment; import java.lang.foreign.ValueLayout; @@ -46,19 +47,8 @@ public byte[] toBytes(boolean includeBody) { } builder.append('\r').append('\n'); if (includeBody) { - writeBody(memorySegmentBody, builder); + LsmServerUtil.copyMemorySegmentToByteArrayBuilder(memorySegmentBody, builder); } return builder.buffer(); } - - private static void writeBody(MemorySegment memorySegmentBody, ByteArrayBuilder builder) { - MemorySegment.copy( - memorySegmentBody, - ValueLayout.JAVA_BYTE, - 0L, - builder.buffer(), - builder.length(), - (int) memorySegmentBody.byteSize() - ); - } } diff --git a/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/GET-30k.txt b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/GET-30k.txt new file mode 100644 index 000000000..9495e0c3e --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/GET-30k.txt @@ -0,0 +1,130 @@ +Running 1m test @ http://localhost:8080 + 4 threads and 64 connections + Thread calibration: mean lat.: 2737.519ms, rate sampling interval: 10002ms + Thread calibration: mean lat.: 2751.135ms, rate sampling interval: 10027ms + Thread calibration: mean lat.: 2748.293ms, rate sampling interval: 10010ms + Thread calibration: mean lat.: 2738.065ms, rate sampling interval: 10010ms + Thread Stats Avg Stdev Max +/- Stdev + Latency 19.15s 7.91s 33.08s 57.83% + Req/Sec 3.40k 14.14 3.42k 62.50% + Latency Distribution (HdrHistogram - Recorded Latency) + 50.000% 19.12s + 75.000% 25.99s + 90.000% 30.21s + 99.000% 32.65s + 99.900% 32.92s + 99.990% 33.01s + 99.999% 33.08s +100.000% 33.10s + + Detailed Percentile spectrum: + Value Percentile TotalCount 1/(1-Percentile) + + 5480.447 0.000000 2 1.00 + 8237.055 0.100000 67690 1.11 + 10919.935 0.200000 135297 1.25 + 13664.255 0.300000 202876 1.43 + 16375.807 0.400000 270561 1.67 + 19120.127 0.500000 338390 2.00 + 20512.767 0.550000 372151 2.22 + 21856.255 0.600000 405822 2.50 + 23216.127 0.650000 439825 2.86 + 24608.767 0.700000 473661 3.33 + 25985.023 0.750000 507440 4.00 + 26656.767 0.775000 524135 4.44 + 27328.511 0.800000 541004 5.00 + 28033.023 0.825000 558037 5.71 + 28721.151 0.850000 575082 6.67 + 29392.895 0.875000 591835 8.00 + 29868.031 0.887500 600424 8.89 + 30212.095 0.900000 608795 10.00 + 30556.159 0.912500 617331 11.43 + 30900.223 0.925000 625807 13.33 + 31227.903 0.937500 634113 16.00 + 31391.743 0.943750 638349 17.78 + 31571.967 0.950000 642788 20.00 + 31735.807 0.956250 646720 22.86 + 31916.031 0.962500 651240 26.67 + 32079.871 0.968750 655309 32.00 + 32161.791 0.971875 657371 35.56 + 32243.711 0.975000 659403 40.00 + 32325.631 0.978125 661460 45.71 + 32407.551 0.981250 663545 53.33 + 32505.855 0.984375 666066 64.00 + 32538.623 0.985938 666853 71.11 + 32587.775 0.987500 668100 80.00 + 32620.543 0.989062 668938 91.43 + 32669.695 0.990625 670189 106.67 + 32702.463 0.992188 671000 128.00 + 32735.231 0.992969 671833 142.22 + 32751.615 0.993750 672240 160.00 + 32767.999 0.994531 672639 182.86 + 32800.767 0.995313 673431 213.33 + 32817.151 0.996094 673820 256.00 + 32833.535 0.996484 674200 284.44 + 32833.535 0.996875 674200 320.00 + 32849.919 0.997266 674555 365.71 + 32866.303 0.997656 674889 426.67 + 32882.687 0.998047 675210 512.00 + 32882.687 0.998242 675210 568.89 + 32882.687 0.998437 675210 640.00 + 32899.071 0.998633 675452 731.43 + 32899.071 0.998828 675452 853.33 + 32915.455 0.999023 675655 1024.00 + 32915.455 0.999121 675655 1137.78 + 32931.839 0.999219 675812 1280.00 + 32931.839 0.999316 675812 1462.86 + 32948.223 0.999414 675942 1706.67 + 32948.223 0.999512 675942 2048.00 + 32948.223 0.999561 675942 2275.56 + 32964.607 0.999609 676038 2560.00 + 32964.607 0.999658 676038 2925.71 + 32964.607 0.999707 676038 3413.33 + 32980.991 0.999756 676093 4096.00 + 32980.991 0.999780 676093 4551.11 + 32980.991 0.999805 676093 5120.00 + 32997.375 0.999829 676131 5851.43 + 32997.375 0.999854 676131 6826.67 + 33013.759 0.999878 676155 8192.00 + 33013.759 0.999890 676155 9102.22 + 33013.759 0.999902 676155 10240.00 + 33030.143 0.999915 676174 11702.86 + 33030.143 0.999927 676174 13653.33 + 33046.527 0.999939 676202 16384.00 + 33046.527 0.999945 676202 18204.44 + 33046.527 0.999951 676202 20480.00 + 33046.527 0.999957 676202 23405.71 + 33046.527 0.999963 676202 27306.67 + 33046.527 0.999969 676202 32768.00 + 33062.911 0.999973 676213 36408.89 + 33062.911 0.999976 676213 40960.00 + 33062.911 0.999979 676213 46811.43 + 33062.911 0.999982 676213 54613.33 + 33062.911 0.999985 676213 65536.00 + 33062.911 0.999986 676213 72817.78 + 33062.911 0.999988 676213 81920.00 + 33079.295 0.999989 676220 93622.86 + 33079.295 0.999991 676220 109226.67 + 33079.295 0.999992 676220 131072.00 + 33079.295 0.999993 676220 145635.56 + 33079.295 0.999994 676220 163840.00 + 33079.295 0.999995 676220 187245.71 + 33079.295 0.999995 676220 218453.33 + 33079.295 0.999996 676220 262144.00 + 33079.295 0.999997 676220 291271.11 + 33079.295 0.999997 676220 327680.00 + 33079.295 0.999997 676220 374491.43 + 33079.295 0.999998 676220 436906.67 + 33079.295 0.999998 676220 524288.00 + 33079.295 0.999998 676220 582542.22 + 33079.295 0.999998 676220 655360.00 + 33095.679 0.999999 676221 748982.86 + 33095.679 1.000000 676221 inf +#[Mean = 19147.619, StdDeviation = 7905.395] +#[Max = 33079.296, Total count = 676221] +#[Buckets = 27, SubBuckets = 2048] +---------------------------------------------------------- + 811430 requests in 1.00m, 39.88MB read + Non-2xx or 3xx responses: 31216 +Requests/sec: 13523.69 +Transfer/sec: 680.56KB diff --git a/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/GET-8k-af-alloc.html b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/GET-8k-af-alloc.html new file mode 100644 index 000000000..96bea451c --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/GET-8k-af-alloc.html @@ -0,0 +1,3279 @@ + + + + + + + +

Allocation profile

+
  
+
Produced by async-profiler
+ +
+

+

Matched:

+ diff --git a/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/GET-8k-af-cpu.html b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/GET-8k-af-cpu.html new file mode 100644 index 000000000..fa936084b --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/GET-8k-af-cpu.html @@ -0,0 +1,5748 @@ + + + + + + + +

CPU profile

+
  
+
Produced by async-profiler
+ +
+

+

Matched:

+ diff --git a/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/GET-8k-af-lock.html b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/GET-8k-af-lock.html new file mode 100644 index 000000000..362d8107d --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/GET-8k-af-lock.html @@ -0,0 +1,1059 @@ + + + + + + + +

Lock profile

+
  
+
Produced by async-profiler
+ +
+

+

Matched:

+ diff --git a/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/GET-8k-after-fix.txt b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/GET-8k-after-fix.txt new file mode 100644 index 000000000..8fa882837 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/GET-8k-after-fix.txt @@ -0,0 +1,126 @@ +Running 1m test @ http://localhost:8080 + 4 threads and 64 connections + Thread calibration: mean lat.: 1.370ms, rate sampling interval: 10ms + Thread calibration: mean lat.: 1.458ms, rate sampling interval: 10ms + Thread calibration: mean lat.: 1.332ms, rate sampling interval: 10ms + Thread calibration: mean lat.: 1.344ms, rate sampling interval: 10ms + Thread Stats Avg Stdev Max +/- Stdev + Latency 1.35ms 607.24us 17.31ms 69.39% + Req/Sec 2.11k 161.56 3.44k 69.74% + Latency Distribution (HdrHistogram - Recorded Latency) + 50.000% 1.30ms + 75.000% 1.72ms + 90.000% 2.13ms + 99.000% 2.95ms + 99.900% 3.86ms + 99.990% 10.17ms + 99.999% 13.06ms +100.000% 17.33ms + + Detailed Percentile spectrum: + Value Percentile TotalCount 1/(1-Percentile) + + 0.116 0.000000 1 1.00 + 0.627 0.100000 40026 1.11 + 0.829 0.200000 79998 1.25 + 0.994 0.300000 120015 1.43 + 1.147 0.400000 159823 1.67 + 1.297 0.500000 199814 2.00 + 1.374 0.550000 219856 2.22 + 1.453 0.600000 239738 2.50 + 1.536 0.650000 259632 2.86 + 1.626 0.700000 279634 3.33 + 1.723 0.750000 299547 4.00 + 1.775 0.775000 309515 4.44 + 1.833 0.800000 319574 5.00 + 1.895 0.825000 329614 5.71 + 1.964 0.850000 339565 6.67 + 2.042 0.875000 349468 8.00 + 2.087 0.887500 354520 8.89 + 2.135 0.900000 359530 10.00 + 2.189 0.912500 364522 11.43 + 2.249 0.925000 369560 13.33 + 2.317 0.937500 374402 16.00 + 2.357 0.943750 376981 17.78 + 2.399 0.950000 379429 20.00 + 2.449 0.956250 381888 22.86 + 2.505 0.962500 384397 26.67 + 2.569 0.968750 386929 32.00 + 2.605 0.971875 388166 35.56 + 2.645 0.975000 389378 40.00 + 2.691 0.978125 390633 45.71 + 2.743 0.981250 391873 53.33 + 2.803 0.984375 393133 64.00 + 2.835 0.985938 393745 71.11 + 2.875 0.987500 394396 80.00 + 2.921 0.989062 395000 91.43 + 2.973 0.990625 395623 106.67 + 3.035 0.992188 396249 128.00 + 3.071 0.992969 396559 142.22 + 3.113 0.993750 396874 160.00 + 3.157 0.994531 397186 182.86 + 3.209 0.995313 397497 213.33 + 3.267 0.996094 397807 256.00 + 3.311 0.996484 397959 284.44 + 3.355 0.996875 398114 320.00 + 3.405 0.997266 398272 365.71 + 3.467 0.997656 398427 426.67 + 3.539 0.998047 398580 512.00 + 3.579 0.998242 398658 568.89 + 3.623 0.998437 398739 640.00 + 3.675 0.998633 398816 731.43 + 3.765 0.998828 398893 853.33 + 3.875 0.999023 398970 1024.00 + 3.943 0.999121 399009 1137.78 + 4.077 0.999219 399049 1280.00 + 4.187 0.999316 399087 1462.86 + 4.319 0.999414 399126 1706.67 + 4.807 0.999512 399165 2048.00 + 5.103 0.999561 399185 2275.56 + 5.491 0.999609 399204 2560.00 + 6.031 0.999658 399224 2925.71 + 6.495 0.999707 399243 3413.33 + 7.491 0.999756 399263 4096.00 + 7.903 0.999780 399273 4551.11 + 8.311 0.999805 399282 5120.00 + 8.999 0.999829 399292 5851.43 + 9.223 0.999854 399302 6826.67 + 9.775 0.999878 399313 8192.00 + 9.863 0.999890 399317 9102.22 + 10.191 0.999902 399321 10240.00 + 10.567 0.999915 399326 11702.86 + 10.799 0.999927 399331 13653.33 + 11.055 0.999939 399336 16384.00 + 11.223 0.999945 399339 18204.44 + 11.391 0.999951 399341 20480.00 + 11.559 0.999957 399344 23405.71 + 11.623 0.999963 399346 27306.67 + 11.727 0.999969 399348 32768.00 + 12.159 0.999973 399350 36408.89 + 12.175 0.999976 399351 40960.00 + 12.335 0.999979 399352 46811.43 + 12.551 0.999982 399353 54613.33 + 12.639 0.999985 399354 65536.00 + 12.927 0.999986 399355 72817.78 + 13.055 0.999988 399356 81920.00 + 13.055 0.999989 399356 93622.86 + 13.391 0.999991 399357 109226.67 + 13.391 0.999992 399357 131072.00 + 13.495 0.999993 399358 145635.56 + 13.495 0.999994 399358 163840.00 + 13.495 0.999995 399358 187245.71 + 13.759 0.999995 399359 218453.33 + 13.759 0.999996 399359 262144.00 + 13.759 0.999997 399359 291271.11 + 13.759 0.999997 399359 327680.00 + 13.759 0.999997 399359 374491.43 + 17.327 0.999998 399360 436906.67 + 17.327 1.000000 399360 inf +#[Mean = 1.354, StdDeviation = 0.607] +#[Max = 17.312, Total count = 399360] +#[Buckets = 27, SubBuckets = 2048] +---------------------------------------------------------- + 479718 requests in 1.00m, 23.57MB read + Non-2xx or 3xx responses: 18126 +Requests/sec: 7995.25 +Transfer/sec: 402.26KB diff --git a/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/GET-8k-alloc.html b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/GET-8k-alloc.html new file mode 100644 index 000000000..25099f087 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/GET-8k-alloc.html @@ -0,0 +1,3209 @@ + + + + + + + +

Allocation profile

+
  
+
Produced by async-profiler
+ +
+

+

Matched:

+ diff --git a/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/GET-8k-cpu.html b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/GET-8k-cpu.html new file mode 100644 index 000000000..67c0127ab --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/GET-8k-cpu.html @@ -0,0 +1,6163 @@ + + + + + + + +

CPU profile

+
  
+
Produced by async-profiler
+ +
+

+

Matched:

+ diff --git a/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/GET-8k-histogram.png b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/GET-8k-histogram.png new file mode 100644 index 000000000..27a487777 Binary files /dev/null and b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/GET-8k-histogram.png differ diff --git a/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/GET-8k-lock.html b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/GET-8k-lock.html new file mode 100644 index 000000000..19079183b --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/GET-8k-lock.html @@ -0,0 +1,1070 @@ + + + + + + + +

Lock profile

+
  
+
Produced by async-profiler
+ +
+

+

Matched:

+ diff --git a/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/GET-8k.txt b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/GET-8k.txt new file mode 100644 index 000000000..81c083ede --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/GET-8k.txt @@ -0,0 +1,126 @@ +Running 1m test @ http://localhost:8080 + 4 threads and 64 connections + Thread calibration: mean lat.: 1.395ms, rate sampling interval: 10ms + Thread calibration: mean lat.: 1.466ms, rate sampling interval: 10ms + Thread calibration: mean lat.: 1.339ms, rate sampling interval: 10ms + Thread calibration: mean lat.: 1.433ms, rate sampling interval: 10ms + Thread Stats Avg Stdev Max +/- Stdev + Latency 1.24ms 620.90us 15.56ms 70.23% + Req/Sec 2.11k 153.09 4.00k 73.39% + Latency Distribution (HdrHistogram - Recorded Latency) + 50.000% 1.17ms + 75.000% 1.60ms + 90.000% 2.03ms + 99.000% 2.96ms + 99.900% 3.96ms + 99.990% 10.31ms + 99.999% 13.86ms +100.000% 15.57ms + + Detailed Percentile spectrum: + Value Percentile TotalCount 1/(1-Percentile) + + 0.114 0.000000 3 1.00 + 0.520 0.100000 40128 1.11 + 0.709 0.200000 79905 1.25 + 0.872 0.300000 119981 1.43 + 1.023 0.400000 159959 1.67 + 1.172 0.500000 199919 2.00 + 1.248 0.550000 219762 2.22 + 1.328 0.600000 239629 2.50 + 1.413 0.650000 259611 2.86 + 1.504 0.700000 279710 3.33 + 1.604 0.750000 299618 4.00 + 1.659 0.775000 309589 4.44 + 1.719 0.800000 319579 5.00 + 1.784 0.825000 329543 5.71 + 1.855 0.850000 339467 6.67 + 1.938 0.875000 349530 8.00 + 1.984 0.887500 354494 8.89 + 2.034 0.900000 359435 10.00 + 2.091 0.912500 364575 11.43 + 2.155 0.925000 369434 13.33 + 2.233 0.937500 374521 16.00 + 2.277 0.943750 376997 17.78 + 2.327 0.950000 379504 20.00 + 2.381 0.956250 381926 22.86 + 2.445 0.962500 384414 26.67 + 2.519 0.968750 386912 32.00 + 2.561 0.971875 388144 35.56 + 2.611 0.975000 389431 40.00 + 2.663 0.978125 390664 45.71 + 2.723 0.981250 391885 53.33 + 2.795 0.984375 393158 64.00 + 2.833 0.985938 393779 71.11 + 2.877 0.987500 394389 80.00 + 2.927 0.989062 395011 91.43 + 2.989 0.990625 395635 106.67 + 3.059 0.992188 396251 128.00 + 3.101 0.992969 396561 142.22 + 3.145 0.993750 396873 160.00 + 3.199 0.994531 397184 182.86 + 3.257 0.995313 397498 213.33 + 3.325 0.996094 397810 256.00 + 3.373 0.996484 397968 284.44 + 3.421 0.996875 398118 320.00 + 3.475 0.997266 398277 365.71 + 3.535 0.997656 398431 426.67 + 3.619 0.998047 398587 512.00 + 3.665 0.998242 398665 568.89 + 3.731 0.998437 398743 640.00 + 3.795 0.998633 398821 731.43 + 3.869 0.998828 398902 853.33 + 3.979 0.999023 398976 1024.00 + 4.063 0.999121 399015 1137.78 + 4.179 0.999219 399058 1280.00 + 4.379 0.999316 399096 1462.86 + 4.639 0.999414 399134 1706.67 + 5.339 0.999512 399171 2048.00 + 5.751 0.999561 399191 2275.56 + 6.127 0.999609 399210 2560.00 + 6.687 0.999658 399230 2925.71 + 7.347 0.999707 399249 3413.33 + 8.015 0.999756 399269 4096.00 + 8.567 0.999780 399279 4551.11 + 8.927 0.999805 399288 5120.00 + 9.119 0.999829 399298 5851.43 + 9.703 0.999854 399308 6826.67 + 10.063 0.999878 399318 8192.00 + 10.175 0.999890 399323 9102.22 + 10.335 0.999902 399327 10240.00 + 10.503 0.999915 399332 11702.86 + 10.695 0.999927 399337 13653.33 + 10.927 0.999939 399342 16384.00 + 11.119 0.999945 399345 18204.44 + 11.231 0.999951 399347 20480.00 + 11.519 0.999957 399349 23405.71 + 11.799 0.999963 399352 27306.67 + 11.991 0.999969 399354 32768.00 + 12.367 0.999973 399356 36408.89 + 12.703 0.999976 399357 40960.00 + 12.719 0.999979 399358 46811.43 + 13.103 0.999982 399359 54613.33 + 13.263 0.999985 399360 65536.00 + 13.527 0.999986 399361 72817.78 + 13.863 0.999988 399362 81920.00 + 13.863 0.999989 399362 93622.86 + 14.231 0.999991 399363 109226.67 + 14.231 0.999992 399363 131072.00 + 14.271 0.999993 399364 145635.56 + 14.271 0.999994 399364 163840.00 + 14.271 0.999995 399364 187245.71 + 14.895 0.999995 399365 218453.33 + 14.895 0.999996 399365 262144.00 + 14.895 0.999997 399365 291271.11 + 14.895 0.999997 399365 327680.00 + 14.895 0.999997 399365 374491.43 + 15.567 0.999998 399366 436906.67 + 15.567 1.000000 399366 inf +#[Mean = 1.244, StdDeviation = 0.621] +#[Max = 15.560, Total count = 399366] +#[Buckets = 27, SubBuckets = 2048] +---------------------------------------------------------- + 479724 requests in 1.00m, 23.58MB read + Non-2xx or 3xx responses: 18709 +Requests/sec: 7995.27 +Transfer/sec: 402.43KB diff --git a/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/PUT-25k-histogram.png b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/PUT-25k-histogram.png new file mode 100644 index 000000000..559d7307a Binary files /dev/null and b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/PUT-25k-histogram.png differ diff --git a/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/PUT-25k.txt b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/PUT-25k.txt new file mode 100644 index 000000000..339fa7c53 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/PUT-25k.txt @@ -0,0 +1,134 @@ +Running 1m test @ http://localhost:8080 + 4 threads and 64 connections + Thread calibration: mean lat.: 216.928ms, rate sampling interval: 1547ms + Thread calibration: mean lat.: 219.273ms, rate sampling interval: 1563ms + Thread calibration: mean lat.: 51.288ms, rate sampling interval: 470ms + Thread calibration: mean lat.: 217.368ms, rate sampling interval: 1554ms + Thread Stats Avg Stdev Max +/- Stdev + Latency 1.35ms 609.01us 8.03ms 70.39% + Req/Sec 6.25k 8.63 6.28k 76.12% + Latency Distribution (HdrHistogram - Recorded Latency) + 50.000% 1.27ms + 75.000% 1.70ms + 90.000% 2.13ms + 99.000% 3.20ms + 99.900% 4.40ms + 99.990% 5.68ms + 99.999% 7.04ms +100.000% 8.03ms + + Detailed Percentile spectrum: + Value Percentile TotalCount 1/(1-Percentile) + + 0.107 0.000000 1 1.00 + 0.645 0.100000 125277 1.11 + 0.826 0.200000 249850 1.25 + 0.978 0.300000 375123 1.43 + 1.123 0.400000 499386 1.67 + 1.271 0.500000 624719 2.00 + 1.348 0.550000 687198 2.22 + 1.427 0.600000 749034 2.50 + 1.511 0.650000 811413 2.86 + 1.601 0.700000 874023 3.33 + 1.701 0.750000 936253 4.00 + 1.756 0.775000 967440 4.44 + 1.816 0.800000 998699 5.00 + 1.880 0.825000 1029609 5.71 + 1.953 0.850000 1061037 6.67 + 2.035 0.875000 1092070 8.00 + 2.081 0.887500 1107614 8.89 + 2.133 0.900000 1123722 10.00 + 2.189 0.912500 1139263 11.43 + 2.251 0.925000 1154665 13.33 + 2.323 0.937500 1170175 16.00 + 2.365 0.943750 1177968 17.78 + 2.411 0.950000 1185622 20.00 + 2.465 0.956250 1193543 22.86 + 2.527 0.962500 1201322 26.67 + 2.603 0.968750 1209133 32.00 + 2.649 0.971875 1212961 35.56 + 2.701 0.975000 1216901 40.00 + 2.765 0.978125 1220762 45.71 + 2.839 0.981250 1224590 53.33 + 2.939 0.984375 1228503 64.00 + 2.999 0.985938 1230467 71.11 + 3.069 0.987500 1232421 80.00 + 3.147 0.989062 1234353 91.43 + 3.239 0.990625 1236288 106.67 + 3.345 0.992188 1238243 128.00 + 3.409 0.992969 1239214 142.22 + 3.481 0.993750 1240195 160.00 + 3.555 0.994531 1241174 182.86 + 3.645 0.995313 1242144 213.33 + 3.741 0.996094 1243107 256.00 + 3.797 0.996484 1243602 284.44 + 3.865 0.996875 1244089 320.00 + 3.933 0.997266 1244579 365.71 + 4.007 0.997656 1245063 426.67 + 4.099 0.998047 1245561 512.00 + 4.147 0.998242 1245783 568.89 + 4.199 0.998437 1246032 640.00 + 4.263 0.998633 1246275 731.43 + 4.331 0.998828 1246519 853.33 + 4.407 0.999023 1246767 1024.00 + 4.451 0.999121 1246880 1137.78 + 4.519 0.999219 1247006 1280.00 + 4.587 0.999316 1247125 1462.86 + 4.659 0.999414 1247246 1706.67 + 4.755 0.999512 1247367 2048.00 + 4.803 0.999561 1247429 2275.56 + 4.867 0.999609 1247490 2560.00 + 4.935 0.999658 1247550 2925.71 + 5.031 0.999707 1247611 3413.33 + 5.119 0.999756 1247672 4096.00 + 5.183 0.999780 1247702 4551.11 + 5.235 0.999805 1247733 5120.00 + 5.299 0.999829 1247764 5851.43 + 5.403 0.999854 1247795 6826.67 + 5.523 0.999878 1247824 8192.00 + 5.595 0.999890 1247839 9102.22 + 5.715 0.999902 1247856 10240.00 + 5.759 0.999915 1247871 11702.86 + 5.815 0.999927 1247885 13653.33 + 5.935 0.999939 1247900 16384.00 + 5.979 0.999945 1247908 18204.44 + 6.051 0.999951 1247916 20480.00 + 6.143 0.999957 1247923 23405.71 + 6.315 0.999963 1247931 27306.67 + 6.531 0.999969 1247938 32768.00 + 6.667 0.999973 1247942 36408.89 + 6.691 0.999976 1247946 40960.00 + 6.735 0.999979 1247950 46811.43 + 6.795 0.999982 1247954 54613.33 + 6.895 0.999985 1247957 65536.00 + 6.963 0.999986 1247959 72817.78 + 6.991 0.999988 1247961 81920.00 + 7.015 0.999989 1247963 93622.86 + 7.135 0.999991 1247965 109226.67 + 7.231 0.999992 1247967 131072.00 + 7.335 0.999993 1247968 145635.56 + 7.375 0.999994 1247969 163840.00 + 7.379 0.999995 1247970 187245.71 + 7.471 0.999995 1247971 218453.33 + 7.519 0.999996 1247972 262144.00 + 7.519 0.999997 1247972 291271.11 + 7.563 0.999997 1247973 327680.00 + 7.563 0.999997 1247973 374491.43 + 7.627 0.999998 1247974 436906.67 + 7.627 0.999998 1247974 524288.00 + 7.627 0.999998 1247974 582542.22 + 7.795 0.999998 1247975 655360.00 + 7.795 0.999999 1247975 748982.86 + 7.795 0.999999 1247975 873813.33 + 7.795 0.999999 1247975 1048576.00 + 7.795 0.999999 1247975 1165084.44 + 8.035 0.999999 1247976 1310720.00 + 8.035 1.000000 1247976 inf +#[Mean = 1.348, StdDeviation = 0.609] +#[Max = 8.032, Total count = 1247976] +#[Buckets = 27, SubBuckets = 2048] +---------------------------------------------------------- + 1492888 requests in 1.00m, 95.39MB read + Non-2xx or 3xx responses: 7 +Requests/sec: 24881.45 +Transfer/sec: 1.59MB diff --git a/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/PUT-31.5k-af-alloc.html b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/PUT-31.5k-af-alloc.html new file mode 100644 index 000000000..27c1f4187 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/PUT-31.5k-af-alloc.html @@ -0,0 +1,3276 @@ + + + + + + + +

Allocation profile

+
  
+
Produced by async-profiler
+ +
+

+

Matched:

+ diff --git a/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/PUT-31.5k-af-cpu.html b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/PUT-31.5k-af-cpu.html new file mode 100644 index 000000000..8113f6d91 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/PUT-31.5k-af-cpu.html @@ -0,0 +1,7960 @@ + + + + + + + +

CPU profile

+
  
+
Produced by async-profiler
+ +
+

+

Matched:

+ diff --git a/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/PUT-31.5k-af-lock.html b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/PUT-31.5k-af-lock.html new file mode 100644 index 000000000..61761229b --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/PUT-31.5k-af-lock.html @@ -0,0 +1,956 @@ + + + + + + + +

Lock profile

+
  
+
Produced by async-profiler
+ +
+

+

Matched:

+ diff --git a/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/PUT-31.5k-after-fix.txt b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/PUT-31.5k-after-fix.txt new file mode 100644 index 000000000..eb7018905 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/PUT-31.5k-after-fix.txt @@ -0,0 +1,135 @@ +Running 1m test @ http://localhost:8080 + 4 threads and 64 connections + Thread calibration: mean lat.: 5.188ms, rate sampling interval: 14ms + Thread calibration: mean lat.: 5.123ms, rate sampling interval: 14ms + Thread calibration: mean lat.: 5.185ms, rate sampling interval: 13ms + Thread calibration: mean lat.: 5.544ms, rate sampling interval: 24ms + Thread Stats Avg Stdev Max +/- Stdev + Latency 2.25ms 1.34ms 13.90ms 82.68% + Req/Sec 8.16k 672.58 10.50k 71.96% + Latency Distribution (HdrHistogram - Recorded Latency) + 50.000% 1.87ms + 75.000% 2.62ms + 90.000% 3.92ms + 99.000% 7.36ms + 99.900% 9.93ms + 99.990% 11.80ms + 99.999% 12.97ms +100.000% 13.91ms + + Detailed Percentile spectrum: + Value Percentile TotalCount 1/(1-Percentile) + + 0.142 0.000000 1 1.00 + 1.076 0.100000 157624 1.11 + 1.313 0.200000 314774 1.25 + 1.504 0.300000 472309 1.43 + 1.683 0.400000 629840 1.67 + 1.870 0.500000 786517 2.00 + 1.977 0.550000 865134 2.22 + 2.099 0.600000 944424 2.50 + 2.241 0.650000 1022662 2.86 + 2.411 0.700000 1101193 3.33 + 2.623 0.750000 1179734 4.00 + 2.753 0.775000 1218685 4.44 + 2.909 0.800000 1258248 5.00 + 3.093 0.825000 1297506 5.71 + 3.311 0.850000 1336732 6.67 + 3.581 0.875000 1376003 8.00 + 3.739 0.887500 1395671 8.89 + 3.919 0.900000 1415277 10.00 + 4.131 0.912500 1434906 11.43 + 4.383 0.925000 1454585 13.33 + 4.695 0.937500 1474328 16.00 + 4.875 0.943750 1484062 17.78 + 5.079 0.950000 1493773 20.00 + 5.307 0.956250 1503714 22.86 + 5.555 0.962500 1513515 26.67 + 5.827 0.968750 1523292 32.00 + 5.983 0.971875 1528249 35.56 + 6.147 0.975000 1533100 40.00 + 6.327 0.978125 1537997 45.71 + 6.535 0.981250 1542934 53.33 + 6.779 0.984375 1547833 64.00 + 6.919 0.985938 1550276 71.11 + 7.075 0.987500 1552741 80.00 + 7.251 0.989062 1555206 91.43 + 7.447 0.990625 1557684 106.67 + 7.667 0.992188 1560101 128.00 + 7.791 0.992969 1561365 142.22 + 7.931 0.993750 1562591 160.00 + 8.083 0.994531 1563794 182.86 + 8.271 0.995313 1565038 213.33 + 8.503 0.996094 1566263 256.00 + 8.615 0.996484 1566862 284.44 + 8.743 0.996875 1567487 320.00 + 8.887 0.997266 1568104 365.71 + 9.055 0.997656 1568700 426.67 + 9.263 0.998047 1569329 512.00 + 9.375 0.998242 1569623 568.89 + 9.503 0.998437 1569943 640.00 + 9.647 0.998633 1570241 731.43 + 9.783 0.998828 1570544 853.33 + 9.951 0.999023 1570857 1024.00 + 10.047 0.999121 1571012 1137.78 + 10.143 0.999219 1571166 1280.00 + 10.263 0.999316 1571310 1462.86 + 10.407 0.999414 1571469 1706.67 + 10.583 0.999512 1571623 2048.00 + 10.663 0.999561 1571700 2275.56 + 10.751 0.999609 1571769 2560.00 + 10.847 0.999658 1571846 2925.71 + 10.991 0.999707 1571923 3413.33 + 11.143 0.999756 1572002 4096.00 + 11.215 0.999780 1572039 4551.11 + 11.327 0.999805 1572077 5120.00 + 11.415 0.999829 1572117 5851.43 + 11.543 0.999854 1572153 6826.67 + 11.663 0.999878 1572194 8192.00 + 11.719 0.999890 1572213 9102.22 + 11.823 0.999902 1572230 10240.00 + 11.887 0.999915 1572252 11702.86 + 11.967 0.999927 1572268 13653.33 + 12.031 0.999939 1572289 16384.00 + 12.071 0.999945 1572297 18204.44 + 12.135 0.999951 1572307 20480.00 + 12.239 0.999957 1572317 23405.71 + 12.295 0.999963 1572327 27306.67 + 12.407 0.999969 1572336 32768.00 + 12.495 0.999973 1572340 36408.89 + 12.559 0.999976 1572345 40960.00 + 12.583 0.999979 1572350 46811.43 + 12.735 0.999982 1572355 54613.33 + 12.831 0.999985 1572360 65536.00 + 12.847 0.999986 1572362 72817.78 + 12.927 0.999988 1572364 81920.00 + 12.967 0.999989 1572368 93622.86 + 13.079 0.999991 1572369 109226.67 + 13.207 0.999992 1572372 131072.00 + 13.223 0.999993 1572373 145635.56 + 13.247 0.999994 1572374 163840.00 + 13.287 0.999995 1572375 187245.71 + 13.383 0.999995 1572376 218453.33 + 13.527 0.999996 1572378 262144.00 + 13.527 0.999997 1572378 291271.11 + 13.631 0.999997 1572379 327680.00 + 13.631 0.999997 1572379 374491.43 + 13.679 0.999998 1572380 436906.67 + 13.767 0.999998 1572381 524288.00 + 13.767 0.999998 1572381 582542.22 + 13.767 0.999998 1572381 655360.00 + 13.767 0.999999 1572381 748982.86 + 13.807 0.999999 1572382 873813.33 + 13.807 0.999999 1572382 1048576.00 + 13.807 0.999999 1572382 1165084.44 + 13.807 0.999999 1572382 1310720.00 + 13.807 0.999999 1572382 1497965.71 + 13.911 0.999999 1572383 1747626.67 + 13.911 1.000000 1572383 inf +#[Mean = 2.251, StdDeviation = 1.344] +#[Max = 13.904, Total count = 1572383] +#[Buckets = 27, SubBuckets = 2048] +---------------------------------------------------------- + 1881040 requests in 1.00m, 120.19MB read +Requests/sec: 31351.04 +Transfer/sec: 2.00MB diff --git a/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/PUT-31.5k-histogram.png b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/PUT-31.5k-histogram.png new file mode 100644 index 000000000..119a1faad Binary files /dev/null and b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/PUT-31.5k-histogram.png differ diff --git a/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/PUT-31.5k.txt b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/PUT-31.5k.txt new file mode 100644 index 000000000..831ae28a1 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/PUT-31.5k.txt @@ -0,0 +1,136 @@ +Running 1m test @ http://localhost:8080 + 4 threads and 64 connections + Thread calibration: mean lat.: 1.803ms, rate sampling interval: 10ms + Thread calibration: mean lat.: 1.809ms, rate sampling interval: 10ms + Thread calibration: mean lat.: 1.765ms, rate sampling interval: 10ms + Thread calibration: mean lat.: 1.798ms, rate sampling interval: 10ms + Thread Stats Avg Stdev Max +/- Stdev + Latency 1.79ms 0.88ms 12.33ms 77.46% + Req/Sec 8.30k 813.43 12.00k 72.55% + Latency Distribution (HdrHistogram - Recorded Latency) + 50.000% 1.63ms + 75.000% 2.19ms + 90.000% 2.82ms + 99.000% 4.61ms + 99.900% 8.77ms + 99.990% 11.05ms + 99.999% 11.90ms +100.000% 12.34ms + + Detailed Percentile spectrum: + Value Percentile TotalCount 1/(1-Percentile) + + 0.151 0.000000 1 1.00 + 0.912 0.100000 157489 1.11 + 1.121 0.200000 314672 1.25 + 1.297 0.300000 472163 1.43 + 1.463 0.400000 629627 1.67 + 1.632 0.500000 786782 2.00 + 1.724 0.550000 865672 2.22 + 1.822 0.600000 943707 2.50 + 1.932 0.650000 1022565 2.86 + 2.055 0.700000 1101504 3.33 + 2.195 0.750000 1180344 4.00 + 2.271 0.775000 1219478 4.44 + 2.353 0.800000 1258149 5.00 + 2.445 0.825000 1297882 5.71 + 2.547 0.850000 1336623 6.67 + 2.669 0.875000 1376147 8.00 + 2.739 0.887500 1395692 8.89 + 2.819 0.900000 1415677 10.00 + 2.907 0.912500 1435119 11.43 + 3.011 0.925000 1454895 13.33 + 3.135 0.937500 1474363 16.00 + 3.209 0.943750 1484202 17.78 + 3.293 0.950000 1494044 20.00 + 3.389 0.956250 1503798 22.86 + 3.505 0.962500 1513645 26.67 + 3.643 0.968750 1523428 32.00 + 3.723 0.971875 1528261 35.56 + 3.817 0.975000 1533243 40.00 + 3.921 0.978125 1538110 45.71 + 4.049 0.981250 1543033 53.33 + 4.203 0.984375 1547987 64.00 + 4.295 0.985938 1550409 71.11 + 4.403 0.987500 1552910 80.00 + 4.527 0.989062 1555334 91.43 + 4.679 0.990625 1557761 106.67 + 4.883 0.992188 1560225 128.00 + 5.003 0.992969 1561454 142.22 + 5.159 0.993750 1562657 160.00 + 5.363 0.994531 1563900 182.86 + 5.635 0.995313 1565117 213.33 + 6.039 0.996094 1566343 256.00 + 6.303 0.996484 1566961 284.44 + 6.619 0.996875 1567573 320.00 + 6.959 0.997266 1568188 365.71 + 7.295 0.997656 1568798 426.67 + 7.663 0.998047 1569411 512.00 + 7.883 0.998242 1569722 568.89 + 8.107 0.998437 1570026 640.00 + 8.327 0.998633 1570336 731.43 + 8.567 0.998828 1570643 853.33 + 8.799 0.999023 1570946 1024.00 + 8.959 0.999121 1571100 1137.78 + 9.135 0.999219 1571255 1280.00 + 9.327 0.999316 1571411 1462.86 + 9.495 0.999414 1571564 1706.67 + 9.687 0.999512 1571714 2048.00 + 9.815 0.999561 1571790 2275.56 + 9.935 0.999609 1571870 2560.00 + 10.087 0.999658 1571947 2925.71 + 10.231 0.999707 1572023 3413.33 + 10.383 0.999756 1572098 4096.00 + 10.463 0.999780 1572136 4551.11 + 10.567 0.999805 1572174 5120.00 + 10.663 0.999829 1572214 5851.43 + 10.775 0.999854 1572252 6826.67 + 10.919 0.999878 1572290 8192.00 + 10.983 0.999890 1572309 9102.22 + 11.063 0.999902 1572332 10240.00 + 11.111 0.999915 1572347 11702.86 + 11.167 0.999927 1572367 13653.33 + 11.255 0.999939 1572388 16384.00 + 11.279 0.999945 1572396 18204.44 + 11.327 0.999951 1572405 20480.00 + 11.375 0.999957 1572415 23405.71 + 11.479 0.999963 1572426 27306.67 + 11.543 0.999969 1572434 32768.00 + 11.567 0.999973 1572438 36408.89 + 11.615 0.999976 1572443 40960.00 + 11.647 0.999979 1572448 46811.43 + 11.719 0.999982 1572454 54613.33 + 11.775 0.999985 1572458 65536.00 + 11.783 0.999986 1572460 72817.78 + 11.831 0.999988 1572462 81920.00 + 11.903 0.999989 1572465 93622.86 + 11.943 0.999991 1572467 109226.67 + 11.999 0.999992 1572470 131072.00 + 12.015 0.999993 1572471 145635.56 + 12.023 0.999994 1572472 163840.00 + 12.039 0.999995 1572473 187245.71 + 12.047 0.999995 1572474 218453.33 + 12.111 0.999996 1572476 262144.00 + 12.111 0.999997 1572476 291271.11 + 12.119 0.999997 1572477 327680.00 + 12.119 0.999997 1572477 374491.43 + 12.175 0.999998 1572478 436906.67 + 12.191 0.999998 1572479 524288.00 + 12.191 0.999998 1572479 582542.22 + 12.191 0.999998 1572479 655360.00 + 12.191 0.999999 1572479 748982.86 + 12.295 0.999999 1572480 873813.33 + 12.295 0.999999 1572480 1048576.00 + 12.295 0.999999 1572480 1165084.44 + 12.295 0.999999 1572480 1310720.00 + 12.295 0.999999 1572480 1497965.71 + 12.335 0.999999 1572481 1747626.67 + 12.335 1.000000 1572481 inf +#[Mean = 1.794, StdDeviation = 0.878] +#[Max = 12.328, Total count = 1572481] +#[Buckets = 27, SubBuckets = 2048] +---------------------------------------------------------- + 1888766 requests in 1.00m, 120.68MB read + Non-2xx or 3xx responses: 1 +Requests/sec: 31479.48 +Transfer/sec: 2.01MB diff --git a/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/PUT-31k-alloc.html b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/PUT-31k-alloc.html new file mode 100644 index 000000000..453ca2b90 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/PUT-31k-alloc.html @@ -0,0 +1,3270 @@ + + + + + + + +

Allocation profile

+
  
+
Produced by async-profiler
+ +
+

+

Matched:

+ diff --git a/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/PUT-31k-cpu.html b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/PUT-31k-cpu.html new file mode 100644 index 000000000..5c8690069 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/PUT-31k-cpu.html @@ -0,0 +1,7859 @@ + + + + + + + +

CPU profile

+
  
+
Produced by async-profiler
+ +
+

+

Matched:

+ diff --git a/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/PUT-31k-lock.html b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/PUT-31k-lock.html new file mode 100644 index 000000000..fae255f47 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/PUT-31k-lock.html @@ -0,0 +1,941 @@ + + + + + + + +

Lock profile

+
  
+
Produced by async-profiler
+ +
+

+

Matched:

+ diff --git a/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/PUT-60k.txt b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/PUT-60k.txt new file mode 100644 index 000000000..3de1bc93c --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/PUT-60k.txt @@ -0,0 +1,119 @@ +Running 1m test @ http://localhost:8080 + 4 threads and 64 connections + Thread calibration: mean lat.: 1509.704ms, rate sampling interval: 6045ms + Thread calibration: mean lat.: 1505.639ms, rate sampling interval: 6037ms + Thread calibration: mean lat.: 1508.103ms, rate sampling interval: 6045ms + Thread calibration: mean lat.: 1504.514ms, rate sampling interval: 6037ms + Thread Stats Avg Stdev Max +/- Stdev + Latency 12.97s 5.67s 23.43s 58.22% + Req/Sec 9.02k 283.19 9.27k 87.50% + Latency Distribution (HdrHistogram - Recorded Latency) + 50.000% 12.80s + 75.000% 17.84s + 90.000% 20.92s + 99.000% 23.17s + 99.900% 23.38s + 99.990% 23.41s + 99.999% 23.43s +100.000% 23.45s + + Detailed Percentile spectrum: + Value Percentile TotalCount 1/(1-Percentile) + + 3379.199 0.000000 1 1.00 + 5283.839 0.100000 179915 1.11 + 7159.807 0.200000 359597 1.25 + 8994.815 0.300000 539218 1.43 + 10854.399 0.400000 718700 1.67 + 12795.903 0.500000 898600 2.00 + 13795.327 0.550000 988613 2.22 + 14794.751 0.600000 1078193 2.50 + 15769.599 0.650000 1168130 2.86 + 16793.599 0.700000 1257615 3.33 + 17842.175 0.750000 1348155 4.00 + 18350.079 0.775000 1392525 4.44 + 18841.599 0.800000 1437455 5.00 + 19349.503 0.825000 1482145 5.71 + 19857.407 0.850000 1528086 6.67 + 20381.695 0.875000 1572833 8.00 + 20643.839 0.887500 1594873 8.89 + 20922.367 0.900000 1618081 10.00 + 21184.511 0.912500 1640664 11.43 + 21430.271 0.925000 1662417 13.33 + 21708.799 0.937500 1684268 16.00 + 21872.639 0.943750 1696596 17.78 + 22069.247 0.950000 1707074 20.00 + 22282.239 0.956250 1718382 22.86 + 22462.463 0.962500 1729517 26.67 + 22659.071 0.968750 1741005 32.00 + 22740.991 0.971875 1746397 35.56 + 22822.911 0.975000 1752111 40.00 + 22888.447 0.978125 1757217 45.71 + 22970.367 0.981250 1763934 53.33 + 23035.903 0.984375 1769307 64.00 + 23068.671 0.985938 1771929 71.11 + 23101.439 0.987500 1774467 80.00 + 23134.207 0.989062 1776937 91.43 + 23183.359 0.990625 1781001 106.67 + 23216.127 0.992188 1783702 128.00 + 23232.511 0.992969 1784949 142.22 + 23248.895 0.993750 1786133 160.00 + 23265.279 0.994531 1787247 182.86 + 23281.663 0.995313 1788338 213.33 + 23314.431 0.996094 1790645 256.00 + 23314.431 0.996484 1790645 284.44 + 23330.815 0.996875 1791879 320.00 + 23330.815 0.997266 1791879 365.71 + 23347.199 0.997656 1793065 426.67 + 23347.199 0.998047 1793065 512.00 + 23363.583 0.998242 1794199 568.89 + 23363.583 0.998437 1794199 640.00 + 23363.583 0.998633 1794199 731.43 + 23379.967 0.998828 1795212 853.33 + 23379.967 0.999023 1795212 1024.00 + 23379.967 0.999121 1795212 1137.78 + 23379.967 0.999219 1795212 1280.00 + 23396.351 0.999316 1796004 1462.86 + 23396.351 0.999414 1796004 1706.67 + 23396.351 0.999512 1796004 2048.00 + 23396.351 0.999561 1796004 2275.56 + 23396.351 0.999609 1796004 2560.00 + 23396.351 0.999658 1796004 2925.71 + 23396.351 0.999707 1796004 3413.33 + 23412.735 0.999756 1796376 4096.00 + 23412.735 0.999780 1796376 4551.11 + 23412.735 0.999805 1796376 5120.00 + 23412.735 0.999829 1796376 5851.43 + 23412.735 0.999854 1796376 6826.67 + 23412.735 0.999878 1796376 8192.00 + 23412.735 0.999890 1796376 9102.22 + 23412.735 0.999902 1796376 10240.00 + 23412.735 0.999915 1796376 11702.86 + 23412.735 0.999927 1796376 13653.33 + 23429.119 0.999939 1796494 16384.00 + 23429.119 0.999945 1796494 18204.44 + 23429.119 0.999951 1796494 20480.00 + 23429.119 0.999957 1796494 23405.71 + 23429.119 0.999963 1796494 27306.67 + 23429.119 0.999969 1796494 32768.00 + 23429.119 0.999973 1796494 36408.89 + 23429.119 0.999976 1796494 40960.00 + 23429.119 0.999979 1796494 46811.43 + 23429.119 0.999982 1796494 54613.33 + 23429.119 0.999985 1796494 65536.00 + 23429.119 0.999986 1796494 72817.78 + 23429.119 0.999988 1796494 81920.00 + 23429.119 0.999989 1796494 93622.86 + 23429.119 0.999991 1796494 109226.67 + 23429.119 0.999992 1796494 131072.00 + 23429.119 0.999993 1796494 145635.56 + 23445.503 0.999994 1796505 163840.00 + 23445.503 1.000000 1796505 inf +#[Mean = 12973.783, StdDeviation = 5667.175] +#[Max = 23429.120, Total count = 1796505] +#[Buckets = 27, SubBuckets = 2048] +---------------------------------------------------------- + 2194003 requests in 1.00m, 140.19MB read + Non-2xx or 3xx responses: 1 +Requests/sec: 36566.85 +Transfer/sec: 2.34MB diff --git a/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/report.md b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/report.md new file mode 100644 index 000000000..514acbefa --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage5/report.md @@ -0,0 +1,291 @@ +# Stage 5 + +- [Stage 5](#stage-5) + * [Конфигурация](#Конфигурация) + * [PUT](#put) + + [CPU profile](#cpu-profile) + + [Alloc profile](#alloc-profile) + + [Lock profile](#lock-profile) + * [GET](#get) + + [CPU profile](#cpu-profile-1) + + [Alloc profile](#alloc-profile-1) + + [Lock profile](#lock-profile-1) + * [Асинхронное выполнение локального запроса](#асинхронное-выполнение-локального-запроса) + + [PUT](#put-1) + + [GET](#get-1) + +## Конфигурация + +wrk2 - 64 connections, 4 threads + +Конфигурация кластера - 3 ноды, запущенные в отдельных процессах. Профилируем ноду, на которую шлём все запросы. + +Запросы без параметров ack и from -> по умолчанию реплицирование 2 из 3 + +## PUT + +[PUT-60k.txt](PUT-60k.txt) + +``` + Thread Stats Avg Stdev Max +/- Stdev + Latency 12.97s 5.67s 23.43s 58.22% + Req/Sec 9.02k 283.19 9.27k 87.50% + Latency Distribution (HdrHistogram - Recorded Latency) + 50.000% 12.80s + 75.000% 17.84s + 90.000% 20.92s + 99.000% 23.17s + 99.900% 23.38s + 99.990% 23.41s + 99.999% 23.43s +100.000% 23.45s +---------------------------------------------------------- + 2194003 requests in 1.00m, 140.19MB read + Non-2xx or 3xx responses: 1 +Requests/sec: 36566.85 +Transfer/sec: 2.34MB +``` + +60k RPS мы всё ещё не держим, но показатели лучше, чем в [прошлой реализации](../stage4/PUT-60k.txt) - wrk удалось +пропихнуть на 6.5k RPS больше. Посмотрим, что происходит на нагрузке в 25k RPS: + +[PUT-25k.txt](PUT-25k.txt) + +``` + Thread Stats Avg Stdev Max +/- Stdev + Latency 1.35ms 609.01us 8.03ms 70.39% + Req/Sec 6.25k 8.63 6.28k 76.12% + Latency Distribution (HdrHistogram - Recorded Latency) + 50.000% 1.27ms + 75.000% 1.70ms + 90.000% 2.13ms + 99.000% 3.20ms + 99.900% 4.40ms + 99.990% 5.68ms + 99.999% 7.04ms +100.000% 8.03ms +``` + +![PUT-25k-histogram.png](PUT-25k-histogram.png) + +Latency на нагрузке в 25k RPS уменьшились в 2 раза, а график теперь похож на прямую зависимость. +Имеет смысл найти новую точку разладки. Очевидно, что это где-то между 25k и 36.5k (столько максимум смог впихнуть wrk +при требуемой от него нагрузки в 60k RPS). + +Путём экспериментов была выбрана точка разладки в 31.5к RPS. + +[PUT-31.5k.txt](PUT-31.5k.txt) + +``` + Thread Stats Avg Stdev Max +/- Stdev + Latency 1.79ms 0.88ms 12.33ms 77.46% + Req/Sec 8.30k 813.43 12.00k 72.55% + Latency Distribution (HdrHistogram - Recorded Latency) + 50.000% 1.63ms + 75.000% 2.19ms + 90.000% 2.82ms + 99.000% 4.61ms + 99.900% 8.77ms + 99.990% 11.05ms + 99.999% 11.90ms +100.000% 12.34ms +``` + +![PUT-31.5k-histogram.png](PUT-31.5k-histogram.png) + +Благодаря асинхронным операциям удалось нарастить пропускную способность нашего кластера на 26%. Теперь мы по-настоящему +ждём 2 успешных ответа из 3 и после этого отвечаем на запрос, соответственно, 1/3 самых медленных запросов выполняется, +но мы не ждём их полного завершения. Это в целом коррелирует с приростом в 26%. + +### CPU profile + +[PUT-31k-cpu.html](PUT-31k-cpu.html) + +На профиле также, как и в [прошлый раз](../stage4/report.md#cpu-profile) видно работу GC - 6% от общего числа сэмплов. + +Уменьшилось количество сэмплов метода `handleEntityRequest` по сравнению +с [предыдущим stage](../stage4/PUT-25k-cpu.html): + +1. В 2 раза меньше сэмплов в методе `processRemote`, так как теперь мы обрабатываем ответы в + отдельном `ExecutorService`. +2. `LsmCustomSession::sendResponse` выполняется тоже асинхронно в отдельном `ExecutorService`. + +В остальном профиль в целом такой же. + +### Alloc profile + +Аллокации не изменились (в рамках погрешности) (раньше было так [PUT-25k-alloc.html](../stage4/PUT-25k-alloc.html)): + +[PUT-31k-alloc.html](PUT-31k-alloc.html) + +### Lock profile + +[PUT-31k-lock.html](PUT-31k-lock.html) + +Блокировки относительно [прошлого результата](../stage4/PUT-25k-lock.html) изменились: + +1. Появились явные блокировки на `HttpClient` при вызове метода `sendAsync`. +2. Блокировки на методе `HttpClient::cancelTimer` из-за того, что таймаут теперь реализуется не с помощью + метода `CompletableFututre::get`, а при создании запроса через builder. +3. Блокировки на внутренних локах `HttpClient` +4. Почти исчезли блокировки на `EPollSelectorImpl::wakeup` - вероятно из-за лучшей утилизации пула потоков, который мы + передали в `HttpClient`, ведь теперь мы не последовательно выполняем 1, а потом второй запрос (в рамках одного + пришедшего запроса), а 2 запроса параллельно, что, вероятно, позволяет потокам не ждать события сокета, а заниматься + обработкой других запросов. + +## GET + +База объемом ~1.5G, каждая нода хранит около 517mb. + +[GET-30k.txt](GET-30k.txt) + +``` + Thread Stats Avg Stdev Max +/- Stdev + Latency 19.15s 7.91s 33.08s 57.83% + Req/Sec 3.40k 14.14 3.42k 62.50% + Latency Distribution (HdrHistogram - Recorded Latency) + 50.000% 19.12s + 75.000% 25.99s + 90.000% 30.21s + 99.000% 32.65s + 99.900% 32.92s + 99.990% 33.01s + 99.999% 33.08s +100.000% 33.10s +---------------------------------------------------------- + 811430 requests in 1.00m, 39.88MB read + Non-2xx or 3xx responses: 31216 +Requests/sec: 13523.69 +Transfer/sec: 680.56KB +``` + +Ошибки Non-2xx or 3xx responses связаны с тем, что иногда мы ищем ключ, которого нет в нашем dao. + +Показатели latency GET запросов тоже стали лучше относительно [прошлого результата](../stage4/GET-30k.txt). wrk уже смог +пропихнуть не 10k RPS, а 13.5k. + +[GET-8k.txt](GET-8k.txt) + +``` + Thread Stats Avg Stdev Max +/- Stdev + Latency 1.24ms 620.90us 15.56ms 70.23% + Req/Sec 2.11k 153.09 4.00k 73.39% + Latency Distribution (HdrHistogram - Recorded Latency) + 50.000% 1.17ms + 75.000% 1.60ms + 90.000% 2.03ms + 99.000% 2.96ms + 99.900% 3.96ms + 99.990% 10.31ms + 99.999% 13.86ms +100.000% 15.57ms +``` + +Но точка разладки по всей видимости примерно такая же, как и была (либо поднялась, но на незначительные показатели). + +![GET-8k-histogram.png](GET-8k-histogram.png) + +### CPU profile + +[GET-8k-cpu.html](GET-8k-cpu.html) + +1. В 2 раза меньше сэмплов в методе `processRemote`, так как теперь мы обрабатываем ответы в + отдельном `ExecutorService`. +2. `LsmCustomSession::sendResponse` выполняется тоже асинхронно в отдельном `ExecutorService` - пропали столбики из + метода `handleEntityRequest`. +3. Чуть-чуть больше стало (~1% против 0.33% ранее) сэмплов GC - вероятно из-за того, что асинхронные операции добавили + разных аллокаций внутреннего мира `HttpClient`. + +В остальном профиль не поменялся относительно [прошлого](../stage4/GET-8k-cpu-2.html). + +### Alloc profile + +[GET-8k-alloc.html](GET-8k-alloc.html) + +С точки зрения аллокаций тут всё снова примерно также, как и [было](../stage4/GET-8k-alloc-2.html). + +Меньше аллокаций в методе `purgeExpiredConnectionsAndReturnNextDeadline` - 2% сэмплов было, а стало 0.09%. Скорее всего +мы теперь лучше переиспользуем соединения. + +### Lock profile + +[GET-8k-lock.html](GET-8k-lock.html) + +Локи изменились сильнее: + +1. Также, как и в PUT, появились явные блокировки на `HttpClient` при вызове метода `sendAsync` из-за асинхронности - + ранее 2 запроса к кластеру выполнялись последовательно, а теперь параллельно и один из них всегда ждёт лок. +2. Появились блокировки на методе `HttpClient::registerTimer` из-за того, что таймаут теперь реализуется не с помощью + метода `CompletableFututre::get`, а при создании запроса через builder. +3. Количество сэмплов на `purgeExpiredConnectionsAndReturnNextDeadline` тоже увеличилось. Вероятно, стало больше гонок + из-за параллельного выполнения запросов к кластеру - отсюда и локи. + +## Асинхронное выполнение локального запроса + +### PUT + +[PUT-31.5k-after-fix.txt](PUT-31.5k-after-fix.txt) + +``` + Thread Stats Avg Stdev Max +/- Stdev + Latency 2.25ms 1.34ms 13.90ms 82.68% + Req/Sec 8.16k 672.58 10.50k 71.96% + Latency Distribution (HdrHistogram - Recorded Latency) + 50.000% 1.87ms + 75.000% 2.62ms + 90.000% 3.92ms + 99.000% 7.36ms + 99.900% 9.93ms + 99.990% 11.80ms + 99.999% 12.97ms +100.000% 13.91ms +``` + +Относительно результатов выше новые показатели отличаются незначительно - latency 99.999-100.000% увеличились на 1ms. +Вероятнее всего это может быть связано с дополнительными переключениями контекста при отправке запроса на выполнение в +отдельный `ExecutorService`. + +[PUT-31.5k-af-cpu.html](PUT-31.5k-af-cpu.html) + +Профиль CPU практически не изменился. Единственное, что поменялось - теперь "столбик" с вызовом `processLocal` отделился +от `processRemote`. Это естественно, ведь теперь мы запускаем локальную обработку асинхронно. + +[PUT-31.5k-af-alloc.html](PUT-31.5k-af-alloc.html) + +[PUT-31.5k-af-lock.html](PUT-31.5k-af-lock.html) + +Остальные профили изменились в рамках погрешности. + +### GET + +[GET-8k-after-fix.txt](GET-8k-after-fix.txt) + +``` + Thread Stats Avg Stdev Max +/- Stdev + Latency 1.35ms 607.24us 17.31ms 69.39% + Req/Sec 2.11k 161.56 3.44k 69.74% + Latency Distribution (HdrHistogram - Recorded Latency) + 50.000% 1.30ms + 75.000% 1.72ms + 90.000% 2.13ms + 99.000% 2.95ms + 99.900% 3.86ms + 99.990% 10.17ms + 99.999% 13.06ms +100.000% 17.33ms +``` + +У GET запросов изменился лишь 100-й перцентиль задержек - он стал на 2ms больше. Опять же вероятно связано с +переключениями контекстов, но на GET запросы не такое влияние, как на PUT, так как тут нагрузка почти в 4 раза меньше, +да и сами GET запросы тяжелее. + +[GET-8k-af-cpu.html](GET-8k-af-cpu.html) + +Профиль CPU практически не изменился. Единственное, что поменялось - теперь "столбик" с вызовом `processLocal` отделился +от `processRemote`. Это естественно, ведь теперь мы запускаем локальную обработку асинхронно. + +[GET-8k-af-alloc.html](GET-8k-af-alloc.html) + +[GET-8k-af-lock.html](GET-8k-af-lock.html) + +Остальные профили практически не изменились, показатели одинаковы в рамках погрешности. diff --git a/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage6/RANGE-alloc.html b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage6/RANGE-alloc.html new file mode 100644 index 000000000..b911a3e3c --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage6/RANGE-alloc.html @@ -0,0 +1,306 @@ + + + + + + + +

Allocation profile

+
  
+
Produced by async-profiler
+ +
+

+

Matched:

+ diff --git a/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage6/RANGE-cpu.html b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage6/RANGE-cpu.html new file mode 100644 index 000000000..f4eb898be --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage6/RANGE-cpu.html @@ -0,0 +1,434 @@ + + + + + + + +

CPU profile

+
  
+
Produced by async-profiler
+ +
+

+

Matched:

+ diff --git a/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage6/RANGE-lock.html b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage6/RANGE-lock.html new file mode 100644 index 000000000..ef7bf570d --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage6/RANGE-lock.html @@ -0,0 +1,260 @@ + + + + + + + +

Lock profile

+
  
+
Produced by async-profiler
+ +
+

+

Matched:

+ diff --git a/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage6/report.md b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage6/report.md new file mode 100644 index 000000000..33a652d2a --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/reports/stage6/report.md @@ -0,0 +1,41 @@ +# Stage 6 + +- [Stage 6](#stage-6) + * [Конфигурация](#Конфигурация) + * [CPU profile](#cpu-profile) + * [Alloc profile](#alloc-profile) + * [Lock profile](#lock-profile) + +## Конфигурация + +Наполнение одной ноды - 1335Mb (1.3Gb). Все ключи имеют вид `key%d+`. + +Запрос: `curl -vvv 'http://localhost:8080/v0/entities?start=key'` + +## CPU profile + +[RANGE-cpu.html](RANGE-cpu.html) + +Почти все сэмплы занимает операция сдвига итераторов. Во время сдвига мы удаляем и добавляем итераторы обратно в очередь. +Каждая такая операция сопровождается сравнением ключей `MemorySegment`. Сравнения были заинлайнены компилятором. +Сравнения также были оптимизированы с помощью векторных инструкций. + +Из интересного - `MemorySegment::copy` использует avx512 при копировании данных в `ByteArrayBuilder`. + +Такое количество сэмплов на операцию сдвига итераторов объясняется тем, что у нас дублируются данные в Sstable, поэтому +нам приходится скипать ключи. + +## Alloc profile + +[RANGE-alloc.html](RANGE-alloc.html) + +Аллокации невероятно красивые - всё, что нам приходится тут аллоцировать, так это `TimestampedEntry` (но без этого никак, +такой у нас интерфейс) и `MemorySegment`. При этом аллокации `MemorySegment` происходят лишь в методе +`MergeIterator::next`, то есть при сдвигах итераторов мы не аллоцируем память, а сравниваем `MemorySegment`'ы прямиком +на диске (а точнее скорее всего в page cache). Достойно уважения. + +## Lock profile + +[RANGE-lock.html](RANGE-lock.html) + +Локи пустые. Блокирующих операций у нас действительно нет. diff --git a/src/main/java/ru/vk/itmo/test/viktorkorotkikh/util/ClusterResponseMerger.java b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/util/ClusterResponseMerger.java new file mode 100644 index 000000000..d38bdbc05 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/util/ClusterResponseMerger.java @@ -0,0 +1,68 @@ +package ru.vk.itmo.test.viktorkorotkikh.util; + +import one.nio.http.HttpSession; +import one.nio.http.Request; +import one.nio.http.Response; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.net.HttpURLConnection; +import java.util.concurrent.atomic.AtomicInteger; + +public class ClusterResponseMerger { + private static final Logger log = LoggerFactory.getLogger(ClusterResponseMerger.class); + private final int ack; + private final int allowedUnsuccessfulResponses; + private final Request originalRequest; + private final HttpSession session; + private final NodeResponse[] nodeResponses; + private final AtomicInteger unsuccessfulResponsesCount; + private final AtomicInteger successfulResponsesCount; + + public ClusterResponseMerger(int ack, int from, Request originalRequest, HttpSession session) { + this.ack = ack; + this.allowedUnsuccessfulResponses = from - ack; + this.originalRequest = originalRequest; + this.session = session; + this.nodeResponses = new NodeResponse[from]; + this.unsuccessfulResponsesCount = new AtomicInteger(); + this.successfulResponsesCount = new AtomicInteger(); + } + + public void addToMerge(int index, NodeResponse response) { + nodeResponses[index] = response; + if (isSuccessfulResponse(response.statusCode())) { + int newSuccessfulResponsesCount = successfulResponsesCount.incrementAndGet(); + if (newSuccessfulResponsesCount == ack) { + sendResponse(); + } + return; + } + int newUnsuccessfulResponsesCount = unsuccessfulResponsesCount.incrementAndGet(); + if (newUnsuccessfulResponsesCount > allowedUnsuccessfulResponses && successfulResponsesCount.get() < ack) { + sendResponseAndCloseSessionOnError(LSMConstantResponse.notEnoughReplicas(originalRequest)); + } + } + + private void sendResponse() { + Response response = LsmServerUtil.mergeReplicasResponses(originalRequest, nodeResponses, ack); + sendResponseAndCloseSessionOnError(response); + } + + private void sendResponseAndCloseSessionOnError(final Response response) { + try { + session.sendResponse(response); + } catch (IOException ex) { + log.error("I/O error occurred when sending response"); + session.scheduleClose(); + } + } + + private static boolean isSuccessfulResponse(int responseStatusCode) { + return responseStatusCode == HttpURLConnection.HTTP_OK + || responseStatusCode == HttpURLConnection.HTTP_CREATED + || responseStatusCode == HttpURLConnection.HTTP_ACCEPTED + || responseStatusCode == HttpURLConnection.HTTP_NOT_FOUND; + } +} diff --git a/src/main/java/ru/vk/itmo/test/viktorkorotkikh/util/LSMConstantResponse.java b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/util/LSMConstantResponse.java index 79cca831e..ea460842b 100644 --- a/src/main/java/ru/vk/itmo/test/viktorkorotkikh/util/LSMConstantResponse.java +++ b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/util/LSMConstantResponse.java @@ -22,6 +22,7 @@ public final class LSMConstantResponse { public static final Response GATEWAY_TIMEOUT_CLOSE = new Response(Response.GATEWAY_TIMEOUT, Response.EMPTY); public static final Response NOT_ENOUGH_REPLICAS_CLOSE = new Response(NOT_ENOUGH_REPLICAS, Response.EMPTY); + public static final byte[] CHUNKED_RESPONSE_CLOSE_WITH_HEADERS_BYTES; private static final String CONNECTION_KEEP_ALIVE_HEADER = "Connection: Keep-Alive"; public static final Response BAD_REQUEST_KEEP_ALIVE = new Response(Response.BAD_REQUEST, Response.EMPTY); @@ -40,6 +41,7 @@ public final class LSMConstantResponse { new Response(Response.GATEWAY_TIMEOUT, Response.EMPTY); public static final Response NOT_ENOUGH_REPLICAS_KEEP_ALIVE = new Response(NOT_ENOUGH_REPLICAS, Response.EMPTY); + public static final byte[] CHUNKED_RESPONSE_KEEP_ALIVE_WITH_HEADERS_BYTES; static { BAD_REQUEST_CLOSE.addHeader(CONNECTION_CLOSE_HEADER); @@ -65,6 +67,16 @@ public final class LSMConstantResponse { SERVICE_UNAVAILABLE_KEEP_ALIVE.addHeader(CONNECTION_KEEP_ALIVE_HEADER); GATEWAY_TIMEOUT_KEEP_ALIVE.addHeader(CONNECTION_KEEP_ALIVE_HEADER); NOT_ENOUGH_REPLICAS_KEEP_ALIVE.addHeader(CONNECTION_KEEP_ALIVE_HEADER); + + Response chunkedResponseKeepAlive = new Response(Response.OK); + chunkedResponseKeepAlive.addHeader("Transfer-Encoding: chunked"); + chunkedResponseKeepAlive.addHeader(CONNECTION_KEEP_ALIVE_HEADER); + CHUNKED_RESPONSE_KEEP_ALIVE_WITH_HEADERS_BYTES = chunkedResponseKeepAlive.toBytes(false); + + Response chunkedResponseClose = new Response(Response.OK); + chunkedResponseKeepAlive.addHeader("Transfer-Encoding: chunked"); + chunkedResponseKeepAlive.addHeader(CONNECTION_CLOSE_HEADER); + CHUNKED_RESPONSE_CLOSE_WITH_HEADERS_BYTES = chunkedResponseClose.toBytes(false); } public static Response ok(final Request request) { diff --git a/src/main/java/ru/vk/itmo/test/viktorkorotkikh/util/LsmServerUtil.java b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/util/LsmServerUtil.java index ebd45d1d5..5dc1ac38b 100644 --- a/src/main/java/ru/vk/itmo/test/viktorkorotkikh/util/LsmServerUtil.java +++ b/src/main/java/ru/vk/itmo/test/viktorkorotkikh/util/LsmServerUtil.java @@ -2,8 +2,11 @@ import one.nio.http.Request; import one.nio.http.Response; +import one.nio.util.ByteArrayBuilder; -import java.util.List; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.ValueLayout; +import java.util.NoSuchElementException; import static java.net.HttpURLConnection.HTTP_BAD_REQUEST; import static java.net.HttpURLConnection.HTTP_ENTITY_TOO_LARGE; @@ -24,7 +27,7 @@ public static String timestampToHeader(long timestamp) { public static Response mergeReplicasResponses( final Request originalRequest, - final List responses, + final NodeResponse[] responses, final int ack ) { switch (originalRequest.getMethod()) { @@ -41,11 +44,12 @@ public static Response mergeReplicasResponses( } } - private static Response mergeGetResponses(Request originalRequest, List responses, int ack) { + private static Response mergeGetResponses(Request originalRequest, NodeResponse[] responses, int ack) { long maxTimestamp = -1; NodeResponse lastValue = null; int successfulResponses = 0; for (NodeResponse response : responses) { + if (response == null) continue; final long valueTimestamp = getTimestamp(response); if (valueTimestamp > maxTimestamp) { maxTimestamp = valueTimestamp; @@ -59,10 +63,10 @@ private static Response mergeGetResponses(Request originalRequest, List lastValue.okResponse(); + case HTTP_OK -> Response.ok(lastValue.body()); case HTTP_BAD_REQUEST -> LSMConstantResponse.badRequest(originalRequest); case HTTP_NOT_FOUND -> LSMConstantResponse.notFound(originalRequest); case HTTP_ENTITY_TOO_LARGE -> LSMConstantResponse.entityTooLarge(originalRequest); @@ -74,7 +78,7 @@ private static Response mergeGetResponses(Request originalRequest, List responses, + NodeResponse[] responses, int ack ) { if (hasNotEnoughReplicas(responses, ack)) { @@ -85,7 +89,7 @@ private static Response mergePutResponses( private static Response mergeDeleteResponses( Request originalRequest, - List responses, + NodeResponse[] responses, int ack ) { if (hasNotEnoughReplicas(responses, ack)) { @@ -94,9 +98,10 @@ private static Response mergeDeleteResponses( return LSMConstantResponse.accepted(originalRequest); } - private static boolean hasNotEnoughReplicas(List responses, int ack) { + private static boolean hasNotEnoughReplicas(NodeResponse[] responses, int ack) { int successfulResponses = 0; for (NodeResponse response : responses) { + if (response == null) continue; if (response.statusCode() >= 200 && response.statusCode() < 300) { successfulResponses++; } @@ -111,4 +116,37 @@ private static long getTimestamp(final NodeResponse response) { } return Long.parseLong(timestamp); } + + private static NodeResponse firstNotNull(NodeResponse[] responses) { + for (NodeResponse response : responses) { + if (response != null) return response; + } + throw new NoSuchElementException(); + } + + public static int copyMemorySegmentToByteArrayBuilder(MemorySegment memorySegmentBody, ByteArrayBuilder builder) { + return copyMemorySegmentToByteArrayBuilder(memorySegmentBody, 0, builder, builder.capacity()); + } + + public static int copyMemorySegmentToByteArrayBuilder( + MemorySegment memorySegment, + int memorySegmentOffset, + ByteArrayBuilder builder, + int builderCapacity + ) { + int estimatedCapacityInBuffer = builderCapacity - builder.length(); + int toWrite = memorySegment.byteSize() > estimatedCapacityInBuffer + ? estimatedCapacityInBuffer + : (int) memorySegment.byteSize() - memorySegmentOffset; + MemorySegment.copy( + memorySegment, + ValueLayout.JAVA_BYTE, + memorySegmentOffset, + builder.buffer(), + builder.length(), + toWrite + ); + builder.setLength(builder.length() + toWrite); + return toWrite; + } }