From 6f77b25a95bb249e05ad90a0020f7e886a59fcc1 Mon Sep 17 00:00:00 2001 From: Vadim Tsesko Date: Sun, 11 Feb 2024 18:31:54 +0300 Subject: [PATCH 01/23] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7c9d938ea..0a12f1212 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # 2024-highload-dht -Курсовой проект 2024 года [курса «Разработка high-load систем»](https://education.vk.company/curriculum/program/discipline/1856/) [Корпоративной магистерской программы «Распределённые веб-сервисы / Web scale systems»](https://dws.itmo.ru/). +Курсовой проект 2024 года [курса «Разработка high-load систем»](https://education.vk.company/curriculum/program/discipline/2007/) [Корпоративной магистерской программы «Распределённые веб-сервисы / Web scale systems»](https://dws.itmo.ru/). ## Этап 1. HTTP + storage (deadline 2024-02-21 23:59:59 MSK) ### Fork From 66c9e0c8de9d1ceebc67b5781f0cb05d97414259 Mon Sep 17 00:00:00 2001 From: sbread Date: Wed, 21 Feb 2024 21:36:44 +0300 Subject: [PATCH 02/23] hw1 without profiling --- .../vk/itmo/test/osipovdaniil/ServerImpl.java | 101 ++++++ .../test/osipovdaniil/ServiceFactoryImpl.java | 14 + .../itmo/test/osipovdaniil/ServiceImpl.java | 44 +++ .../osipovdaniil/dao/ByteArraySegment.java | 48 +++ .../dao/LiveFilteringIterator.java | 52 ++++ .../itmo/test/osipovdaniil/dao/MemTable.java | 49 +++ .../dao/MemorySegmentComparator.java | 89 ++++++ .../dao/MergingEntryIterator.java | 68 ++++ .../test/osipovdaniil/dao/ReferenceDao.java | 292 ++++++++++++++++++ .../itmo/test/osipovdaniil/dao/SSTable.java | 204 ++++++++++++ .../test/osipovdaniil/dao/SSTableWriter.java | 166 ++++++++++ .../itmo/test/osipovdaniil/dao/SSTables.java | 162 ++++++++++ .../itmo/test/osipovdaniil/dao/TableSet.java | 201 ++++++++++++ .../dao/WeightedPeekingEntryIterator.java | 67 ++++ 14 files changed, 1557 insertions(+) create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/ServiceFactoryImpl.java create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/ServiceImpl.java create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/dao/ByteArraySegment.java create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/dao/LiveFilteringIterator.java create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/dao/MemTable.java create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/dao/MemorySegmentComparator.java create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/dao/MergingEntryIterator.java create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/dao/ReferenceDao.java create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/dao/SSTable.java create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/dao/SSTableWriter.java create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/dao/SSTables.java create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/dao/TableSet.java create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/dao/WeightedPeekingEntryIterator.java diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java new file mode 100644 index 000000000..dc120c648 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java @@ -0,0 +1,101 @@ +package ru.vk.itmo.test.osipovdaniil; + +import one.nio.http.*; +import one.nio.server.AcceptorConfig; +import ru.vk.itmo.ServiceConfig; +import ru.vk.itmo.dao.BaseEntry; +import ru.vk.itmo.dao.Entry; +import ru.vk.itmo.test.osipovdaniil.dao.ReferenceDao; + +import java.io.IOException; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.ValueLayout; +import java.nio.charset.StandardCharsets; +import java.util.function.Function; + +public class ServerImpl extends HttpServer { + + private static final String ENTITY_PATH = "/v0/entity"; + + private final ReferenceDao dao; + + public ServerImpl(final ServiceConfig serviceConfig, ReferenceDao dao) throws IOException { + super(createHttpServerConfig(serviceConfig)); + this.dao = dao; + } + + private static HttpServerConfig createHttpServerConfig(final ServiceConfig serviceConfig) { + final HttpServerConfig httpServerConfig = new HttpServerConfig(); + final AcceptorConfig acceptorConfig = new AcceptorConfig(); + acceptorConfig.port = serviceConfig.selfPort(); + acceptorConfig.reusePort = true; + httpServerConfig.acceptors = new AcceptorConfig[] { acceptorConfig }; + httpServerConfig.closeSessions = true; + return httpServerConfig; + } + + private boolean validateId(final String id) { + return id != null && !id.isEmpty(); + } + + private Response requestHandle(final String id, final Function request) { + if (!validateId(id)) { + return new Response(Response.BAD_REQUEST, ("invalid id: " + id).getBytes(StandardCharsets.UTF_8)); + } + final MemorySegment key = MemorySegment.ofArray(id.getBytes(StandardCharsets.UTF_8)); + return request.apply(key); + } + + @Path(ENTITY_PATH) + @RequestMethod(Request.METHOD_GET) + public Response get(@Param("id") final String id) { + return requestHandle(id, + key -> { + final Entry entry = dao.get(key); + return entry != null ? + Response.ok(entry.value().toArray(ValueLayout.JAVA_BYTE)) : + new Response(Response.NOT_FOUND, Response.EMPTY); + }); + } + + @Path(ENTITY_PATH) + @RequestMethod(Request.METHOD_DELETE) + public Response delete(@Param("id") final String id) { + return requestHandle(id, + key -> { + dao.upsert(new BaseEntry<>(key, null)); + return new Response(Response.ACCEPTED, Response.EMPTY); + }); + } + + @Path(ENTITY_PATH) + @RequestMethod(Request.METHOD_PUT) + public Response put(@Param("id") final String id, final Request value) { + return requestHandle(id, + key -> { + dao.upsert(new BaseEntry<>(key, MemorySegment.ofArray(value.getBody()))); + return new Response(Response.CREATED, Response.EMPTY); + }); + } + + @Override + public void handleRequest(final Request request, final HttpSession session) throws IOException { + Response response; + if (!request.getPath().startsWith(ENTITY_PATH)) { + response = new Response(Response.BAD_REQUEST, Response.EMPTY); + session.sendResponse(response); + return; + } + final int method = request.getMethod(); + if (method == Request.METHOD_GET) { + response = get(request.getParameter("id=")); + } else if (method == Request.METHOD_DELETE) { + response = delete(request.getParameter("id=")); + } else if (method == Request.METHOD_PUT) { + response = put(request.getParameter("id="), request); + } else { + response = new Response(Response.METHOD_NOT_ALLOWED, Response.EMPTY); + } + session.sendResponse(response); + } +} diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/ServiceFactoryImpl.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/ServiceFactoryImpl.java new file mode 100644 index 000000000..dd9363932 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/ServiceFactoryImpl.java @@ -0,0 +1,14 @@ +package ru.vk.itmo.test.osipovdaniil; + +import ru.vk.itmo.Service; +import ru.vk.itmo.ServiceConfig; +import ru.vk.itmo.test.ServiceFactory; + +@ServiceFactory(stage = 1) +public class ServiceFactoryImpl implements ServiceFactory.Factory { + + @Override + public Service create(ServiceConfig config) { + return new ServiceImpl(config); + } +} diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/ServiceImpl.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/ServiceImpl.java new file mode 100644 index 000000000..12139c6e5 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/ServiceImpl.java @@ -0,0 +1,44 @@ +package ru.vk.itmo.test.osipovdaniil; + +import ru.vk.itmo.Service; +import ru.vk.itmo.ServiceConfig; +import ru.vk.itmo.dao.Config; +import ru.vk.itmo.test.osipovdaniil.dao.ReferenceDao; + +import java.io.IOException; +import java.util.concurrent.CompletableFuture; + +public class ServiceImpl implements Service { + + public static final long FLUSH_THRESHOLD_BYTES = 1024L * 1024; + private ServerImpl server; + private final ServiceConfig serviceConfig; + private ReferenceDao dao; + + private final Config daoConfig; + + public ServiceImpl(final ServiceConfig serviceConfig) { + this.serviceConfig = serviceConfig; + this.daoConfig = createDaoConfig(serviceConfig); + } + + private static Config createDaoConfig(final ServiceConfig config) { + return new Config(config.workingDir(), FLUSH_THRESHOLD_BYTES); + } + + + @Override + public CompletableFuture start() throws IOException { + this.dao = new ReferenceDao(daoConfig); + this.server = new ServerImpl(serviceConfig, dao); + server.start(); + return CompletableFuture.completedFuture(null); + } + + @Override + public CompletableFuture stop() throws IOException { + server.stop(); + dao.close(); + return CompletableFuture.completedFuture(null); + } +} diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/ByteArraySegment.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/ByteArraySegment.java new file mode 100644 index 000000000..18d8ca11b --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/ByteArraySegment.java @@ -0,0 +1,48 @@ +package ru.vk.itmo.test.osipovdaniil.dao; + +import java.io.IOException; +import java.lang.foreign.MemorySegment; +import java.nio.ByteBuffer; + +/** + * Growable buffer with {@link ByteBuffer} and {@link MemorySegment} interface. + * + * @author incubos + */ +final class ByteArraySegment { + private byte[] array; + private MemorySegment segment; + + ByteArraySegment(final int capacity) { + this.array = new byte[capacity]; + this.segment = MemorySegment.ofArray(array); + } + + void withArray(final ArrayConsumer consumer) throws IOException { + consumer.process(array); + } + + MemorySegment segment() { + return segment; + } + + void ensureCapacity(final long size) { + if (size > Integer.MAX_VALUE) { + throw new IllegalArgumentException("Too big!"); + } + + final int capacity = (int) size; + if (array.length >= capacity) { + return; + } + + // Grow to the nearest bigger power of 2 + final int newSize = Integer.highestOneBit(capacity) << 1; + array = new byte[newSize]; + segment = MemorySegment.ofArray(array); + } + + interface ArrayConsumer { + void process(byte[] array) throws IOException; + } +} diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/LiveFilteringIterator.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/LiveFilteringIterator.java new file mode 100644 index 000000000..c30b99f54 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/LiveFilteringIterator.java @@ -0,0 +1,52 @@ +package ru.vk.itmo.test.osipovdaniil.dao; + +import ru.vk.itmo.dao.Entry; + +import java.lang.foreign.MemorySegment; +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * Filters non tombstone {@link Entry}s. + * + * @author incubos + */ +final class LiveFilteringIterator implements Iterator> { + private final Iterator> delegate; + private Entry next; + + LiveFilteringIterator(final Iterator> delegate) { + this.delegate = delegate; + skipTombstones(); + } + + private void skipTombstones() { + while (delegate.hasNext()) { + final Entry entry = delegate.next(); + if (entry.value() != null) { + this.next = entry; + break; + } + } + } + + @Override + public boolean hasNext() { + return next != null; + } + + @Override + public Entry next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + + // Consume + final Entry result = next; + next = null; + + skipTombstones(); + + return result; + } +} diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/MemTable.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/MemTable.java new file mode 100644 index 000000000..aa38f2feb --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/MemTable.java @@ -0,0 +1,49 @@ +package ru.vk.itmo.test.osipovdaniil.dao; + +import ru.vk.itmo.dao.Entry; + +import java.lang.foreign.MemorySegment; +import java.util.Iterator; +import java.util.NavigableMap; +import java.util.concurrent.ConcurrentSkipListMap; + +/** + * Memory table. + * + * @author incubos + */ +final class MemTable { + private final NavigableMap> map = + new ConcurrentSkipListMap<>( + MemorySegmentComparator.INSTANCE); + + boolean isEmpty() { + return map.isEmpty(); + } + + Iterator> get( + final MemorySegment from, + final MemorySegment to) { + if (from == null && to == null) { + // All + return map.values().iterator(); + } else if (from == null) { + // Head + return map.headMap(to).values().iterator(); + } else if (to == null) { + // Tail + return map.tailMap(from).values().iterator(); + } else { + // Slice + return map.subMap(from, to).values().iterator(); + } + } + + Entry get(final MemorySegment key) { + return map.get(key); + } + + Entry upsert(final Entry entry) { + return map.put(entry.key(), entry); + } +} diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/MemorySegmentComparator.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/MemorySegmentComparator.java new file mode 100644 index 000000000..a313e0cee --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/MemorySegmentComparator.java @@ -0,0 +1,89 @@ +package ru.vk.itmo.test.osipovdaniil.dao; + +import java.lang.foreign.MemorySegment; +import java.lang.foreign.ValueLayout; +import java.util.Comparator; + +/** + * Compares {@link MemorySegment}s. + * + * @author incubos + */ +final class MemorySegmentComparator implements Comparator { + static final Comparator INSTANCE = + new MemorySegmentComparator(); + + private MemorySegmentComparator() { + // Singleton + } + + @Override + public int compare( + final MemorySegment left, + final MemorySegment right) { + final long mismatch = left.mismatch(right); + if (mismatch == -1L) { + // No mismatch + return 0; + } + + if (mismatch == left.byteSize()) { + // left is prefix of right, so left is smaller + return -1; + } + + if (mismatch == right.byteSize()) { + // right is prefix of left, so left is greater + return 1; + } + + // Compare mismatched bytes as unsigned + return Byte.compareUnsigned( + left.getAtIndex( + ValueLayout.OfByte.JAVA_BYTE, + mismatch), + right.getAtIndex( + ValueLayout.OfByte.JAVA_BYTE, + mismatch)); + } + + static int compare( + final MemorySegment srcSegment, + final long srcFromOffset, + final long srcLength, + final MemorySegment dstSegment, + final long dstFromOffset, + final long dstLength) { + final long mismatch = + MemorySegment.mismatch( + srcSegment, + srcFromOffset, + srcFromOffset + srcLength, + dstSegment, + dstFromOffset, + dstFromOffset + dstLength); + if (mismatch == -1L) { + // No mismatch + return 0; + } + + if (mismatch == srcLength) { + // left is prefix of right, so left is smaller + return -1; + } + + if (mismatch == dstLength) { + // right is prefix of left, so left is greater + return 1; + } + + // Compare mismatched bytes as unsigned + return Byte.compareUnsigned( + srcSegment.getAtIndex( + ValueLayout.OfByte.JAVA_BYTE, + srcFromOffset + mismatch), + dstSegment.getAtIndex( + ValueLayout.OfByte.JAVA_BYTE, + dstFromOffset + mismatch)); + } +} diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/MergingEntryIterator.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/MergingEntryIterator.java new file mode 100644 index 000000000..fa78d904e --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/MergingEntryIterator.java @@ -0,0 +1,68 @@ +package ru.vk.itmo.test.osipovdaniil.dao; + +import ru.vk.itmo.dao.Entry; + +import java.lang.foreign.MemorySegment; +import java.util.*; + +/** + * Merges entry {@link Iterator}s. + * + * @author incubos + */ +final class MergingEntryIterator implements Iterator> { + private final Queue iterators; + + MergingEntryIterator(final List iterators) { + assert iterators.stream().allMatch(WeightedPeekingEntryIterator::hasNext); + + this.iterators = new PriorityQueue<>(iterators); + } + + @Override + public boolean hasNext() { + return !iterators.isEmpty(); + } + + @Override + public Entry next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + + final WeightedPeekingEntryIterator top = iterators.remove(); + final Entry result = top.next(); + + if (top.hasNext()) { + // Not exhausted + iterators.add(top); + } + + // Remove older versions of the key + while (true) { + final WeightedPeekingEntryIterator iterator = iterators.peek(); + if (iterator == null) { + // Nothing left + break; + } + + // Skip entries with the same key + final Entry entry = iterator.peek(); + if (MemorySegmentComparator.INSTANCE.compare(result.key(), entry.key()) != 0) { + // Reached another key + break; + } + + // Drop + iterators.remove(); + // Skip + iterator.next(); + if (iterator.hasNext()) { + // Not exhausted + iterators.add(iterator); + } + } + + return result; + } +} diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/ReferenceDao.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/ReferenceDao.java new file mode 100644 index 000000000..5ebda7ae3 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/ReferenceDao.java @@ -0,0 +1,292 @@ +package ru.vk.itmo.test.osipovdaniil.dao; + +import ru.vk.itmo.dao.Config; +import ru.vk.itmo.dao.Dao; +import ru.vk.itmo.dao.Entry; + +import java.io.IOException; +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +/** + * Reference implementation of {@link Dao}. + * + * @author incubos + */ +public class ReferenceDao implements Dao> { + private final Config config; + private final Arena arena; + + private final ReadWriteLock lock = new ReentrantReadWriteLock(); + // Guarded by lock + private volatile TableSet tableSet; + + private final ExecutorService flusher = + Executors.newSingleThreadExecutor(r -> { + final Thread result = new Thread(r); + result.setName("flusher"); + return result; + }); + private final ExecutorService compactor = + Executors.newSingleThreadExecutor(r -> { + final Thread result = new Thread(r); + result.setName("compactor"); + return result; + }); + + private final AtomicBoolean closed = new AtomicBoolean(); + + public ReferenceDao(final Config config) throws IOException { + this.config = config; + this.arena = Arena.ofShared(); + + // First complete promotion of compacted SSTables + SSTables.promote( + config.basePath(), + 0, + 1); + + this.tableSet = + TableSet.from( + SSTables.discover( + arena, + config.basePath())); + } + + @Override + public Iterator> get( + final MemorySegment from, + final MemorySegment to) { + return new LiveFilteringIterator( + tableSet.get( + from, + to)); + } + + @Override + public Entry get(final MemorySegment key) { + // Without lock, just snapshot of table set + return tableSet.get(key); + } + + @Override + public void upsert(final Entry entry) { + final boolean autoFlush; + lock.readLock().lock(); + try { + if (tableSet.memTableSize.get() > config.flushThresholdBytes() + && tableSet.flushingTable != null) { + throw new IllegalStateException("Can't keep up with flushing!"); + } + + // Upsert + final Entry previous = tableSet.upsert(entry); + + // Update size estimate + final long size = tableSet.memTableSize.addAndGet(sizeOf(entry) - sizeOf(previous)); + autoFlush = size > config.flushThresholdBytes(); + } finally { + lock.readLock().unlock(); + } + + if (autoFlush) { + initiateFlush(true); + } + } + + private static long sizeOf(final Entry entry) { + if (entry == null) { + return 0L; + } + + if (entry.value() == null) { + return entry.key().byteSize(); + } + + return entry.key().byteSize() + entry.value().byteSize(); + } + + private void initiateFlush(final boolean auto) { + flusher.submit(() -> { + final TableSet currentTableSet; + lock.writeLock().lock(); + try { + if (this.tableSet.memTable.isEmpty()) { + // Nothing to flush + return; + } + + if (auto && this.tableSet.memTableSize.get() < config.flushThresholdBytes()) { + // Not enough data to flush + return; + } + + // Switch memTable to flushing + currentTableSet = this.tableSet.flushing(); + this.tableSet = currentTableSet; + } finally { + lock.writeLock().unlock(); + } + + // Write + final int sequence = currentTableSet.nextSequence(); + try { + new SSTableWriter() + .write( + config.basePath(), + sequence, + currentTableSet.flushingTable.get(null, null)); + } catch (IOException e) { + e.printStackTrace(); + Runtime.getRuntime().halt(-1); + return; + } + + // Open + final SSTable flushed; + try { + flushed = SSTables.open( + arena, + config.basePath(), + sequence); + } catch (IOException e) { + e.printStackTrace(); + Runtime.getRuntime().halt(-2); + return; + } + + // Switch + lock.writeLock().lock(); + try { + this.tableSet = this.tableSet.flushed(flushed); + } finally { + lock.writeLock().unlock(); + } + }).state(); + } + + @Override + public void flush() throws IOException { + initiateFlush(false); + } + + @Override + public void compact() throws IOException { + compactor.submit(() -> { + final TableSet currentTableSet; + lock.writeLock().lock(); + try { + currentTableSet = this.tableSet; + if (currentTableSet.ssTables.size() < 2) { + // Nothing to compact + return; + } + } finally { + lock.writeLock().unlock(); + } + + // Compact to 0 + try { + new SSTableWriter() + .write( + config.basePath(), + 0, + new LiveFilteringIterator( + currentTableSet.allSSTableEntries())); + } catch (IOException e) { + e.printStackTrace(); + Runtime.getRuntime().halt(-3); + } + + // Open 0 + final SSTable compacted; + try { + compacted = + SSTables.open( + arena, + config.basePath(), + 0); + } catch (IOException e) { + e.printStackTrace(); + Runtime.getRuntime().halt(-4); + return; + } + + // Replace old SSTables with compacted one to + // keep serving requests + final Set replaced = new HashSet<>(currentTableSet.ssTables); + lock.writeLock().lock(); + try { + this.tableSet = + this.tableSet.compacted( + replaced, + compacted); + } finally { + lock.writeLock().unlock(); + } + + // Remove compacted SSTables starting from the oldest ones. + // If we crash, 0 contains all the data, and + // it will be promoted on reopen. + for (final SSTable ssTable : currentTableSet.ssTables.reversed()) { + try { + SSTables.remove( + config.basePath(), + ssTable.sequence); + } catch (IOException e) { + e.printStackTrace(); + Runtime.getRuntime().halt(-5); + } + } + + // Promote zero to one (possibly replacing) + try { + SSTables.promote( + config.basePath(), + 0, + 1); + } catch (IOException e) { + e.printStackTrace(); + Runtime.getRuntime().halt(-6); + } + + // Replace promoted SSTable + lock.writeLock().lock(); + try { + this.tableSet = + this.tableSet.compacted( + Collections.singleton(compacted), + compacted.withSequence(1)); + } finally { + lock.writeLock().unlock(); + } + }).state(); + } + + @Override + public void close() throws IOException { + if (closed.getAndSet(true)) { + // Already closed + return; + } + + // Maybe flush + flush(); + + // Stop all the threads + flusher.close(); + compactor.close(); + + // Close arena + arena.close(); + } +} diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/SSTable.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/SSTable.java new file mode 100644 index 000000000..1c08d2242 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/SSTable.java @@ -0,0 +1,204 @@ +package ru.vk.itmo.test.osipovdaniil.dao; + +import ru.vk.itmo.dao.BaseEntry; +import ru.vk.itmo.dao.Entry; + +import java.lang.foreign.MemorySegment; +import java.lang.foreign.ValueLayout; +import java.util.Collections; +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * Persistent SSTable in data file and index file. + * + * @author incubos + * @see SSTables + */ +final class SSTable { + final int sequence; + + private final MemorySegment index; + private final MemorySegment data; + private final long size; + + SSTable( + final int sequence, + final MemorySegment index, + final MemorySegment data) { + this.sequence = sequence; + this.index = index; + this.data = data; + this.size = index.byteSize() / Long.BYTES; + } + + SSTable withSequence(final int sequence) { + return new SSTable( + sequence, + index, + data); + } + + /** + * Returns index of the entry if found; otherwise, (-(insertion point) - 1). + * The insertion point is defined as the point at which the key would be inserted: + * the index of the first element greater than the key, + * or size if all keys are less than the specified key. + * Note that this guarantees that the return value will be >= 0 + * if and only if the key is found. + */ + private long entryBinarySearch(final MemorySegment key) { + long low = 0L; + long high = size - 1; + + while (low <= high) { + final long mid = (low + high) >>> 1; + final long midEntryOffset = entryOffset(mid); + final long midKeyLength = getLength(midEntryOffset); + final int compare = + MemorySegmentComparator.compare( + data, + midEntryOffset + Long.BYTES, // Position at key + midKeyLength, + key, + 0L, + key.byteSize()); + + if (compare < 0) { + low = mid + 1; + } else if (compare > 0) { + high = mid - 1; + } else { + return mid; + } + } + + return -(low + 1); + } + + private long entryOffset(final long entry) { + return index.get( + ValueLayout.OfLong.JAVA_LONG, + entry * Long.BYTES); + } + + private long getLength(final long offset) { + return data.get( + ValueLayout.OfLong.JAVA_LONG_UNALIGNED, + offset); + } + + Iterator> get( + final MemorySegment from, + final MemorySegment to) { + assert from == null || to == null || MemorySegmentComparator.INSTANCE.compare(from, to) <= 0; + + // Slice of SSTable in absolute offsets + final long fromOffset; + final long toOffset; + + // Left offset bound + if (from == null) { + // Start from the beginning + fromOffset = 0L; + } else { + final long fromEntry = entryBinarySearch(from); + if (fromEntry >= 0L) { + fromOffset = entryOffset(fromEntry); + } else if (-fromEntry - 1 == size) { + // No relevant data + return Collections.emptyIterator(); + } else { + // Greater but existing key found + fromOffset = entryOffset(-fromEntry - 1); + } + } + + // Right offset bound + if (to == null) { + // Up to the end + toOffset = data.byteSize(); + } else { + final long toEntry = entryBinarySearch(to); + if (toEntry >= 0L) { + toOffset = entryOffset(toEntry); + } else if (-toEntry - 1 == size) { + // Up to the end + toOffset = data.byteSize(); + } else { + // Greater but existing key found + toOffset = entryOffset(-toEntry - 1); + } + } + + return new SliceIterator(fromOffset, toOffset); + } + + Entry get(final MemorySegment key) { + final long entry = entryBinarySearch(key); + if (entry < 0) { + return null; + } + + // Skip key (will reuse the argument) + long offset = entryOffset(entry); + offset += Long.BYTES + key.byteSize(); + // Extract value length + final long valueLength = getLength(offset); + if (valueLength == SSTables.TOMBSTONE_VALUE_LENGTH) { + // Tombstone encountered + return new BaseEntry<>(key, null); + } else { + // Get value + offset += Long.BYTES; + final MemorySegment value = data.asSlice(offset, valueLength); + return new BaseEntry<>(key, value); + } + } + + private final class SliceIterator implements Iterator> { + private long offset; + private final long toOffset; + + private SliceIterator( + final long offset, + final long toOffset) { + this.offset = offset; + this.toOffset = toOffset; + } + + @Override + public boolean hasNext() { + return offset < toOffset; + } + + @Override + public Entry next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + + // Read key length + final long keyLength = getLength(offset); + offset += Long.BYTES; + + // Read key + final MemorySegment key = data.asSlice(offset, keyLength); + offset += keyLength; + + // Read value length + final long valueLength = getLength(offset); + offset += Long.BYTES; + + // Read value + if (valueLength == SSTables.TOMBSTONE_VALUE_LENGTH) { + // Tombstone encountered + return new BaseEntry<>(key, null); + } else { + final MemorySegment value = data.asSlice(offset, valueLength); + offset += valueLength; + return new BaseEntry<>(key, value); + } + } + } +} diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/SSTableWriter.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/SSTableWriter.java new file mode 100644 index 000000000..920a0bbb5 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/SSTableWriter.java @@ -0,0 +1,166 @@ +package ru.vk.itmo.test.osipovdaniil.dao; + +import ru.vk.itmo.dao.Entry; + +import java.io.BufferedOutputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.ValueLayout; +import java.nio.channels.FileChannel; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.util.Iterator; + +/** + * Writes {@link Entry} {@link Iterator} to SSTable on disk. + * + *

Index file {@code .index} contains {@code long} offsets to entries in data file: + * {@code [offset0, offset1, ...]} + * + *

Data file {@code .data} contains serialized entries: + * {@code } + * + *

Tombstones are encoded as {@code valueLength} {@code -1} and no subsequent value. + * + * @author incubos + */ +final class SSTableWriter { + private static final int BUFFER_SIZE = 64 * 1024; + + // Reusable buffers to eliminate allocations. + // But excessive memory copying is still there :( + // Long cell + private final ByteArraySegment longBuffer = new ByteArraySegment(Long.BYTES); + // Growable blob cell + private final ByteArraySegment blobBuffer = new ByteArraySegment(512); + + void write( + final Path baseDir, + final int sequence, + final Iterator> entries) throws IOException { + // Write to temporary files + final Path tempIndexName = SSTables.tempIndexName(baseDir, sequence); + final Path tempDataName = SSTables.tempDataName(baseDir, sequence); + + // Delete temporary files to eliminate tails + Files.deleteIfExists(tempIndexName); + Files.deleteIfExists(tempDataName); + + // Iterate in a single pass! + // Will write through FileChannel despite extra memory copying and + // no buffering (which may be implemented later). + // Looking forward to MemorySegment facilities in FileChannel! + try (OutputStream index = + new BufferedOutputStream( + new FileOutputStream( + tempIndexName.toFile()), + BUFFER_SIZE); + OutputStream data = + new BufferedOutputStream( + new FileOutputStream( + tempDataName.toFile()), + BUFFER_SIZE)) { + long entryOffset = 0L; + + // Iterate and serialize + while (entries.hasNext()) { + // First write offset to the entry + writeLong(entryOffset, index); + + // Then write the entry + final Entry entry = entries.next(); + entryOffset += writeEntry(entry, data); + } + } + + // Publish files atomically + // FIRST index, LAST data + final Path indexName = + SSTables.indexName( + baseDir, + sequence); + Files.move( + tempIndexName, + indexName, + StandardCopyOption.ATOMIC_MOVE, + StandardCopyOption.REPLACE_EXISTING); + final Path dataName = + SSTables.dataName( + baseDir, + sequence); + Files.move( + tempDataName, + dataName, + StandardCopyOption.ATOMIC_MOVE, + StandardCopyOption.REPLACE_EXISTING); + } + + private void writeLong( + final long value, + final OutputStream os) throws IOException { + longBuffer.segment().set( + ValueLayout.OfLong.JAVA_LONG_UNALIGNED, + 0, + value); + longBuffer.withArray(os::write); + } + + private void writeSegment( + final MemorySegment value, + final OutputStream os) throws IOException { + final long size = value.byteSize(); + blobBuffer.ensureCapacity(size); + MemorySegment.copy( + value, + 0L, + blobBuffer.segment(), + 0L, + size); + blobBuffer.withArray(array -> + os.write( + array, + 0, + (int) size)); + } + + /** + * Writes {@link Entry} to {@link FileChannel}. + * + * @return written bytes + */ + private long writeEntry( + final Entry entry, + final OutputStream os) throws IOException { + final MemorySegment key = entry.key(); + final MemorySegment value = entry.value(); + long result = 0L; + + // Key size + writeLong(key.byteSize(), os); + result += Long.BYTES; + + // Key + writeSegment(key, os); + result += key.byteSize(); + + // Value size and possibly value + if (value == null) { + // Tombstone + writeLong(SSTables.TOMBSTONE_VALUE_LENGTH, os); + result += Long.BYTES; + } else { + // Value length + writeLong(value.byteSize(), os); + result += Long.BYTES; + + // Value + writeSegment(value, os); + result += value.byteSize(); + } + + return result; + } +} diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/SSTables.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/SSTables.java new file mode 100644 index 000000000..75b0adb6b --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/SSTables.java @@ -0,0 +1,162 @@ +package ru.vk.itmo.test.osipovdaniil.dao; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; +import java.nio.channels.FileChannel; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.nio.file.StandardOpenOption; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Stream; + +/** + * Provides {@link SSTable} management facilities: dumping and discovery. + * + * @author incubos + */ +final class SSTables { + public static final String INDEX_SUFFIX = ".index"; + public static final String DATA_SUFFIX = ".data"; + public static final long TOMBSTONE_VALUE_LENGTH = -1L; + + private static final String TEMP_SUFFIX = ".tmp"; + + /** + * Can't instantiate. + */ + private SSTables() { + // Only static methods + } + + static Path indexName( + final Path baseDir, + final int sequence) { + return baseDir.resolve(sequence + INDEX_SUFFIX); + } + + static Path dataName( + final Path baseDir, + final int sequence) { + return baseDir.resolve(sequence + DATA_SUFFIX); + } + + static Path tempIndexName( + final Path baseDir, + final int sequence) { + return baseDir.resolve(sequence + INDEX_SUFFIX + TEMP_SUFFIX); + } + + static Path tempDataName( + final Path baseDir, + final int sequence) { + return baseDir.resolve(sequence + DATA_SUFFIX + TEMP_SUFFIX); + } + + /** + * Returns {@link List} of {@link SSTable}s from freshest to oldest. + */ + static List discover( + final Arena arena, + final Path baseDir) throws IOException { + if (!Files.exists(baseDir)) { + return Collections.emptyList(); + } + + final List result = new ArrayList<>(); + try (Stream files = Files.list(baseDir)) { + files.forEach(file -> { + final String fileName = file.getFileName().toString(); + if (!fileName.endsWith(DATA_SUFFIX)) { + // Skip non data + return; + } + + final int sequence = + // .data -> N + Integer.parseInt( + fileName.substring( + 0, + fileName.length() - DATA_SUFFIX.length())); + + try { + result.add(open(arena, baseDir, sequence)); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }); + } + + // Sort from freshest to oldest + result.sort((o1, o2) -> Integer.compare(o2.sequence, o1.sequence)); + + return Collections.unmodifiableList(result); + } + + static SSTable open( + final Arena arena, + final Path baseDir, + final int sequence) throws IOException { + final MemorySegment index = + mapReadOnly( + arena, + indexName(baseDir, sequence)); + final MemorySegment data = + mapReadOnly( + arena, + dataName(baseDir, sequence)); + + return new SSTable( + sequence, + index, + data); + } + + private static MemorySegment mapReadOnly( + final Arena arena, + final Path file) throws IOException { + try (FileChannel channel = + FileChannel.open( + file, + StandardOpenOption.READ)) { + return channel.map( + FileChannel.MapMode.READ_ONLY, + 0L, + Files.size(file), + arena); + } + } + + static void remove( + final Path baseDir, + final int sequence) throws IOException { + // First delete data file to make SSTable invisible + Files.delete(dataName(baseDir, sequence)); + Files.delete(indexName(baseDir, sequence)); + } + + static void promote( + final Path baseDir, + final int from, + final int to) throws IOException { + // Build to progress to the same outcome + if (Files.exists(indexName(baseDir, from))) { + Files.move( + indexName(baseDir, from), + indexName(baseDir, to), + StandardCopyOption.ATOMIC_MOVE, + StandardCopyOption.REPLACE_EXISTING); + } + if (Files.exists(dataName(baseDir, from))) { + Files.move( + dataName(baseDir, from), + dataName(baseDir, to), + StandardCopyOption.ATOMIC_MOVE, + StandardCopyOption.REPLACE_EXISTING); + } + } +} diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/TableSet.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/TableSet.java new file mode 100644 index 000000000..2dce67506 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/TableSet.java @@ -0,0 +1,201 @@ +package ru.vk.itmo.test.osipovdaniil.dao; + +import ru.vk.itmo.dao.Entry; + +import java.lang.foreign.MemorySegment; +import java.util.*; +import java.util.concurrent.atomic.AtomicLong; + +/** + * Data set in various tables. + * + * @author incubos + */ +final class TableSet { + final MemTable memTable; + final AtomicLong memTableSize; + // null or read-only + final MemTable flushingTable; + // From freshest to oldest + final List ssTables; + + private TableSet( + final MemTable memTable, + final AtomicLong memTableSize, + final MemTable flushingTable, + final List ssTables) { + this.memTable = memTable; + this.memTableSize = memTableSize; + this.flushingTable = flushingTable; + this.ssTables = ssTables; + } + + static TableSet from(final List ssTables) { + return new TableSet( + new MemTable(), + new AtomicLong(), + null, + ssTables); + } + + int nextSequence() { + return ssTables.stream() + .mapToInt(t -> t.sequence) + .max() + .orElse(0) + 1; + } + + TableSet flushing() { + if (memTable.isEmpty()) { + throw new IllegalStateException("Nothing to flush"); + } + + if (flushingTable != null) { + throw new IllegalStateException("Already flushing"); + } + + return new TableSet( + new MemTable(), + new AtomicLong(), + memTable, + ssTables); + } + + TableSet flushed(final SSTable flushed) { + final List newSSTables = new ArrayList<>(ssTables.size() + 1); + newSSTables.add(flushed); + newSSTables.addAll(ssTables); + return new TableSet( + memTable, + memTableSize, + null, + newSSTables); + } + + TableSet compacted( + final Set replaced, + final SSTable with) { + final List newSsTables = new ArrayList<>(this.ssTables.size() + 1); + + // Keep not replaced SSTables + for (final SSTable ssTable : this.ssTables) { + if (!replaced.contains(ssTable)) { + newSsTables.add(ssTable); + } + } + + // Logically the oldest one + newSsTables.add(with); + + return new TableSet( + memTable, + memTableSize, + flushingTable, + newSsTables); + } + + Iterator> get( + final MemorySegment from, + final MemorySegment to) { + final List iterators = + new ArrayList<>(2 + ssTables.size()); + + // MemTable goes first + final Iterator> memTableIterator = + memTable.get(from, to); + if (memTableIterator.hasNext()) { + iterators.add( + new WeightedPeekingEntryIterator( + Integer.MIN_VALUE, + memTableIterator)); + } + + // Then goes flushing + if (flushingTable != null) { + final Iterator> flushingIterator = + flushingTable.get(from, to); + if (flushingIterator.hasNext()) { + iterators.add( + new WeightedPeekingEntryIterator( + Integer.MIN_VALUE + 1, + flushingIterator)); + } + } + + // Then go all the SSTables + for (int i = 0; i < ssTables.size(); i++) { + final SSTable ssTable = ssTables.get(i); + final Iterator> ssTableIterator = + ssTable.get(from, to); + if (ssTableIterator.hasNext()) { + iterators.add( + new WeightedPeekingEntryIterator( + i, + ssTableIterator)); + } + } + + return switch (iterators.size()) { + case 0 -> Collections.emptyIterator(); + case 1 -> iterators.get(0); + default -> new MergingEntryIterator(iterators); + }; + } + + Entry get(final MemorySegment key) { + // Slightly optimized version not to pollute the heap + + // First check MemTable + Entry result = memTable.get(key); + if (result != null) { + // Transform tombstone + return swallowTombstone(result); + } + + // Then check flushing + if (flushingTable != null) { + result = flushingTable.get(key); + if (result != null) { + // Transform tombstone + return swallowTombstone(result); + } + } + + // At last check SSTables from freshest to oldest + for (final SSTable ssTable : ssTables) { + result = ssTable.get(key); + if (result != null) { + // Transform tombstone + return swallowTombstone(result); + } + } + + // Nothing found + return null; + } + + private static Entry swallowTombstone(final Entry entry) { + return entry.value() == null ? null : entry; + } + + Entry upsert(final Entry entry) { + return memTable.upsert(entry); + } + + Iterator> allSSTableEntries() { + final List iterators = + new ArrayList<>(ssTables.size()); + + for (int i = 0; i < ssTables.size(); i++) { + final SSTable ssTable = ssTables.get(i); + final Iterator> ssTableIterator = + ssTable.get(null, null); + iterators.add( + new WeightedPeekingEntryIterator( + i, + ssTableIterator)); + } + + return new MergingEntryIterator(iterators); + } +} diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/WeightedPeekingEntryIterator.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/WeightedPeekingEntryIterator.java new file mode 100644 index 000000000..91f299d9c --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/WeightedPeekingEntryIterator.java @@ -0,0 +1,67 @@ +package ru.vk.itmo.test.osipovdaniil.dao; + +import ru.vk.itmo.dao.Entry; + +import java.lang.foreign.MemorySegment; +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * Peeking {@link Iterator} wrapper. + * + * @author incubos + */ +final class WeightedPeekingEntryIterator + implements Iterator>, + Comparable { + private final int weight; + private final Iterator> delegate; + private Entry next; + + WeightedPeekingEntryIterator( + final int weight, + final Iterator> delegate) { + this.weight = weight; + this.delegate = delegate; + this.next = delegate.hasNext() ? delegate.next() : null; + } + + @Override + public boolean hasNext() { + return next != null; + } + + @Override + public Entry next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + + final Entry result = next; + next = delegate.hasNext() ? delegate.next() : null; + return result; + } + + Entry peek() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + + return next; + } + + @Override + public int compareTo(final WeightedPeekingEntryIterator other) { + // First compare keys + int result = + MemorySegmentComparator.INSTANCE.compare( + peek().key(), + other.peek().key()); + if (result != 0) { + return result; + } + + // Then compare weights if keys are equal + return Integer.compare(weight, other.weight); + } +} From 539bcb60098af9ebe0323f202f0e260b15e25079 Mon Sep 17 00:00:00 2001 From: sbread Date: Wed, 21 Feb 2024 21:50:04 +0300 Subject: [PATCH 03/23] code climate --- .../vk/itmo/test/osipovdaniil/ServerImpl.java | 17 ++++++++++++----- .../vk/itmo/test/osipovdaniil/ServiceImpl.java | 1 - 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java index dc120c648..0cc0a0cc6 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java @@ -1,6 +1,13 @@ package ru.vk.itmo.test.osipovdaniil; -import one.nio.http.*; +import one.nio.http.HttpServer; +import one.nio.http.HttpServerConfig; +import one.nio.http.HttpSession; +import one.nio.http.Param; +import one.nio.http.Path; +import one.nio.http.RequestMethod; +import one.nio.http.Request; +import one.nio.http.Response; import one.nio.server.AcceptorConfig; import ru.vk.itmo.ServiceConfig; import ru.vk.itmo.dao.BaseEntry; @@ -40,7 +47,7 @@ private boolean validateId(final String id) { private Response requestHandle(final String id, final Function request) { if (!validateId(id)) { - return new Response(Response.BAD_REQUEST, ("invalid id: " + id).getBytes(StandardCharsets.UTF_8)); + return new Response(Response.BAD_REQUEST, (STR."invalid id: \{id}").getBytes(StandardCharsets.UTF_8)); } final MemorySegment key = MemorySegment.ofArray(id.getBytes(StandardCharsets.UTF_8)); return request.apply(key); @@ -52,9 +59,9 @@ public Response get(@Param("id") final String id) { return requestHandle(id, key -> { final Entry entry = dao.get(key); - return entry != null ? - Response.ok(entry.value().toArray(ValueLayout.JAVA_BYTE)) : - new Response(Response.NOT_FOUND, Response.EMPTY); + return entry == null + ? new Response(Response.NOT_FOUND, Response.EMPTY) : + Response.ok(entry.value().toArray(ValueLayout.JAVA_BYTE)); }); } diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/ServiceImpl.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/ServiceImpl.java index 12139c6e5..72dab167c 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/ServiceImpl.java +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/ServiceImpl.java @@ -26,7 +26,6 @@ private static Config createDaoConfig(final ServiceConfig config) { return new Config(config.workingDir(), FLUSH_THRESHOLD_BYTES); } - @Override public CompletableFuture start() throws IOException { this.dao = new ReferenceDao(daoConfig); From 5190066ce65e383c72a942c753bf746d0007a4ad Mon Sep 17 00:00:00 2001 From: sbread Date: Wed, 21 Feb 2024 22:00:03 +0300 Subject: [PATCH 04/23] delete preview STR feature --- src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java index 0cc0a0cc6..6a7aa9173 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java @@ -47,7 +47,7 @@ private boolean validateId(final String id) { private Response requestHandle(final String id, final Function request) { if (!validateId(id)) { - return new Response(Response.BAD_REQUEST, (STR."invalid id: \{id}").getBytes(StandardCharsets.UTF_8)); + return new Response(Response.BAD_REQUEST, ("invalid id: " + id).getBytes(StandardCharsets.UTF_8)); } final MemorySegment key = MemorySegment.ofArray(id.getBytes(StandardCharsets.UTF_8)); return request.apply(key); From 6b5101e030bd9fa7709c5859b851851002413ed3 Mon Sep 17 00:00:00 2001 From: sbread Date: Wed, 21 Feb 2024 22:02:50 +0300 Subject: [PATCH 05/23] code climate --- src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java | 2 +- .../vk/itmo/test/osipovdaniil/dao/MergingEntryIterator.java | 6 +++++- .../java/ru/vk/itmo/test/osipovdaniil/dao/TableSet.java | 6 +++++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java index 6a7aa9173..5f0ec636d 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java @@ -5,8 +5,8 @@ import one.nio.http.HttpSession; import one.nio.http.Param; import one.nio.http.Path; -import one.nio.http.RequestMethod; import one.nio.http.Request; +import one.nio.http.RequestMethod; import one.nio.http.Response; import one.nio.server.AcceptorConfig; import ru.vk.itmo.ServiceConfig; diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/MergingEntryIterator.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/MergingEntryIterator.java index fa78d904e..0d5343f39 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/MergingEntryIterator.java +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/MergingEntryIterator.java @@ -3,7 +3,11 @@ import ru.vk.itmo.dao.Entry; import java.lang.foreign.MemorySegment; -import java.util.*; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.PriorityQueue; +import java.util.Queue; /** * Merges entry {@link Iterator}s. diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/TableSet.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/TableSet.java index 2dce67506..98771eba5 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/TableSet.java +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/TableSet.java @@ -3,7 +3,11 @@ import ru.vk.itmo.dao.Entry; import java.lang.foreign.MemorySegment; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Set; import java.util.concurrent.atomic.AtomicLong; /** From be7a6ec1fe3c707e0279ee0d47096fcf08de1f5d Mon Sep 17 00:00:00 2001 From: sbread Date: Wed, 21 Feb 2024 23:59:22 +0300 Subject: [PATCH 06/23] wrk test --- .../itmo/test/osipovdaniil/scripts/delete.lua | 10 ++ .../vk/itmo/test/osipovdaniil/scripts/get.lua | 10 ++ .../vk/itmo/test/osipovdaniil/scripts/put.lua | 11 ++ .../ru/vk/itmo/test/osipovdaniil/wrk/delete | 118 +++++++++++++++++ .../java/ru/vk/itmo/test/osipovdaniil/wrk/get | 119 ++++++++++++++++++ .../java/ru/vk/itmo/test/osipovdaniil/wrk/put | 118 +++++++++++++++++ 6 files changed, 386 insertions(+) create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/delete.lua create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/get.lua create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/put.lua create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/wrk/delete create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/wrk/get create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/wrk/put diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/delete.lua b/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/delete.lua new file mode 100644 index 000000000..b9f932bd4 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/delete.lua @@ -0,0 +1,10 @@ +id = 0 + +function request() + curId = id + id = id + 1 + path = "/v0/entity?id=key" .. curId + headers = {} + headers["Host"] = "localhost:8080" + return wrk.format("DELETE", path, headers) +end diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/get.lua b/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/get.lua new file mode 100644 index 000000000..3ed630fda --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/get.lua @@ -0,0 +1,10 @@ +id = 0 + +function request() + curId = id + id = id + 1 + path = "/v0/entity?id=key" .. curId + headers = {} + headers["Host"] = "localhost:8080" + return wrk.format("GET", path, headers) +end diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/put.lua b/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/put.lua new file mode 100644 index 000000000..f87fed66c --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/put.lua @@ -0,0 +1,11 @@ +id = 0 + +function request() + curId = id + id = id + 1 + path = "/v0/entity?id=key" .. curId + headers = {} + headers["Host"] = "localhost:8080" + value = "value" .. curId + return wrk.format("PUT", path, headers, value) +end diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/wrk/delete b/src/main/java/ru/vk/itmo/test/osipovdaniil/wrk/delete new file mode 100644 index 000000000..e276951b9 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/wrk/delete @@ -0,0 +1,118 @@ +./wrk -d 30 -t 1 -c 1 -R 10000 -L -s /home/sbread/Desktop/labs/HLS/2024-highload-dht/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/delete.lua http://localhost:8080 +Running 30s test @ http://localhost:8080 + 1 threads and 1 connections + Thread calibration: mean lat.: 0.947ms, rate sampling interval: 10ms + Thread Stats Avg Stdev Max +/- Stdev + Latency 0.90ms 1.76ms 22.32ms 97.52% + Req/Sec 10.60k 0.86k 17.78k 71.72% + Latency Distribution (HdrHistogram - Recorded Latency) + 50.000% 671.00us + 75.000% 0.97ms + 90.000% 1.13ms + 99.000% 9.40ms + 99.900% 21.04ms + 99.990% 22.24ms + 99.999% 22.32ms +100.000% 22.33ms + + Detailed Percentile spectrum: + Value Percentile TotalCount 1/(1-Percentile) + + 0.033 0.000000 1 1.00 + 0.182 0.100000 20085 1.11 + 0.300 0.200000 40089 1.25 + 0.421 0.300000 60117 1.43 + 0.545 0.400000 79991 1.67 + 0.671 0.500000 99998 2.00 + 0.732 0.550000 110018 2.22 + 0.793 0.600000 119965 2.50 + 0.852 0.650000 130055 2.86 + 0.910 0.700000 140003 3.33 + 0.967 0.750000 150105 4.00 + 0.995 0.775000 155086 4.44 + 1.023 0.800000 160024 5.00 + 1.051 0.825000 165123 5.71 + 1.079 0.850000 170113 6.67 + 1.106 0.875000 174990 8.00 + 1.120 0.887500 177538 8.89 + 1.135 0.900000 180003 10.00 + 1.159 0.912500 182504 11.43 + 1.223 0.925000 184947 13.33 + 1.408 0.937500 187434 16.00 + 1.511 0.943750 188696 17.78 + 1.623 0.950000 189937 20.00 + 1.758 0.956250 191183 22.86 + 1.897 0.962500 192437 26.67 + 2.030 0.968750 193687 32.00 + 2.197 0.971875 194311 35.56 + 2.621 0.975000 194931 40.00 + 3.407 0.978125 195556 45.71 + 4.371 0.981250 196186 53.33 + 5.847 0.984375 196807 64.00 + 7.047 0.985938 197118 71.11 + 7.935 0.987500 197430 80.00 + 8.839 0.989062 197743 91.43 + 10.447 0.990625 198055 106.67 + 13.063 0.992188 198369 128.00 + 14.327 0.992969 198525 142.22 + 15.383 0.993750 198680 160.00 + 16.527 0.994531 198837 182.86 + 17.599 0.995313 198992 213.33 + 17.903 0.996094 199152 256.00 + 18.063 0.996484 199230 284.44 + 18.335 0.996875 199307 320.00 + 18.559 0.997266 199385 365.71 + 19.087 0.997656 199464 426.67 + 19.295 0.998047 199544 512.00 + 19.471 0.998242 199579 568.89 + 19.919 0.998437 199617 640.00 + 20.303 0.998633 199656 731.43 + 20.655 0.998828 199695 853.33 + 21.087 0.999023 199734 1024.00 + 21.263 0.999121 199754 1137.78 + 21.359 0.999219 199773 1280.00 + 21.455 0.999316 199793 1462.86 + 21.551 0.999414 199814 1706.67 + 21.615 0.999512 199833 2048.00 + 21.663 0.999561 199844 2275.56 + 21.743 0.999609 199851 2560.00 + 21.855 0.999658 199861 2925.71 + 21.951 0.999707 199872 3413.33 + 22.031 0.999756 199881 4096.00 + 22.079 0.999780 199886 4551.11 + 22.127 0.999805 199890 5120.00 + 22.175 0.999829 199895 5851.43 + 22.207 0.999854 199901 6826.67 + 22.223 0.999878 199906 8192.00 + 22.239 0.999890 199910 9102.22 + 22.239 0.999902 199910 10240.00 + 22.255 0.999915 199914 11702.86 + 22.271 0.999927 199919 13653.33 + 22.271 0.999939 199919 16384.00 + 22.271 0.999945 199919 18204.44 + 22.287 0.999951 199921 20480.00 + 22.287 0.999957 199921 23405.71 + 22.303 0.999963 199924 27306.67 + 22.303 0.999969 199924 32768.00 + 22.303 0.999973 199924 36408.89 + 22.319 0.999976 199928 40960.00 + 22.319 0.999979 199928 46811.43 + 22.319 0.999982 199928 54613.33 + 22.319 0.999985 199928 65536.00 + 22.319 0.999986 199928 72817.78 + 22.319 0.999988 199928 81920.00 + 22.319 0.999989 199928 93622.86 + 22.319 0.999991 199928 109226.67 + 22.319 0.999992 199928 131072.00 + 22.319 0.999993 199928 145635.56 + 22.319 0.999994 199928 163840.00 + 22.319 0.999995 199928 187245.71 + 22.335 0.999995 199929 218453.33 + 22.335 1.000000 199929 inf +#[Mean = 0.901, StdDeviation = 1.755] +#[Max = 22.320, Total count = 199929] +#[Buckets = 27, SubBuckets = 2048] +---------------------------------------------------------- + 299973 requests in 30.00s, 19.45MB read +Requests/sec: 9999.19 +Transfer/sec: 664.01KB diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/wrk/get b/src/main/java/ru/vk/itmo/test/osipovdaniil/wrk/get new file mode 100644 index 000000000..2bba35360 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/wrk/get @@ -0,0 +1,119 @@ +./wrk -d 30 -t 1 -c 1 -R 10000 -L -s /home/sbread/Desktop/labs/HLS/2024-highload-dht/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/get.lua http://localhost:8080 +Running 30s test @ http://localhost:8080 + 1 threads and 1 connections + Thread calibration: mean lat.: 2.912ms, rate sampling interval: 10ms + Thread Stats Avg Stdev Max +/- Stdev + Latency 1.62ms 4.79ms 49.70ms 96.05% + Req/Sec 10.58k 1.02k 25.00k 80.16% + Latency Distribution (HdrHistogram - Recorded Latency) + 50.000% 717.00us + 75.000% 1.03ms + 90.000% 1.85ms + 99.000% 32.19ms + 99.900% 47.81ms + 99.990% 49.38ms + 99.999% 49.66ms +100.000% 49.73ms + + Detailed Percentile spectrum: + Value Percentile TotalCount 1/(1-Percentile) + + 0.034 0.000000 1 1.00 + 0.188 0.100000 20056 1.11 + 0.315 0.200000 40039 1.25 + 0.446 0.300000 60091 1.43 + 0.581 0.400000 80135 1.67 + 0.717 0.500000 100106 2.00 + 0.782 0.550000 110030 2.22 + 0.848 0.600000 120043 2.50 + 0.910 0.650000 129983 2.86 + 0.971 0.700000 140064 3.33 + 1.031 0.750000 150090 4.00 + 1.060 0.775000 155066 4.44 + 1.089 0.800000 160077 5.00 + 1.119 0.825000 165036 5.71 + 1.164 0.850000 170022 6.67 + 1.423 0.875000 174966 8.00 + 1.622 0.887500 177461 8.89 + 1.847 0.900000 179962 10.00 + 2.075 0.912500 182463 11.43 + 2.667 0.925000 184962 13.33 + 3.455 0.937500 187458 16.00 + 3.925 0.943750 188708 17.78 + 4.543 0.950000 189967 20.00 + 5.455 0.956250 191205 22.86 + 7.307 0.962500 192454 26.67 + 8.983 0.968750 193704 32.00 + 10.919 0.971875 194329 35.56 + 12.487 0.975000 194956 40.00 + 13.695 0.978125 195579 45.71 + 16.007 0.981250 196203 53.33 + 21.311 0.984375 196828 64.00 + 24.399 0.985938 197141 71.11 + 27.471 0.987500 197455 80.00 + 30.543 0.989062 197768 91.43 + 33.119 0.990625 198080 106.67 + 35.487 0.992188 198396 128.00 + 36.959 0.992969 198548 142.22 + 38.175 0.993750 198705 160.00 + 39.775 0.994531 198860 182.86 + 41.055 0.995313 199015 213.33 + 42.303 0.996094 199174 256.00 + 42.783 0.996484 199250 284.44 + 43.647 0.996875 199330 320.00 + 44.383 0.997266 199408 365.71 + 45.183 0.997656 199486 426.67 + 45.791 0.998047 199563 512.00 + 46.303 0.998242 199601 568.89 + 46.783 0.998437 199640 640.00 + 47.167 0.998633 199679 731.43 + 47.519 0.998828 199719 853.33 + 47.871 0.999023 199758 1024.00 + 47.967 0.999121 199787 1137.78 + 47.999 0.999219 199797 1280.00 + 48.191 0.999316 199817 1462.86 + 48.383 0.999414 199838 1706.67 + 48.575 0.999512 199857 2048.00 + 48.671 0.999561 199865 2275.56 + 48.767 0.999609 199875 2560.00 + 48.863 0.999658 199884 2925.71 + 48.991 0.999707 199895 3413.33 + 49.151 0.999756 199904 4096.00 + 49.215 0.999780 199910 4551.11 + 49.279 0.999805 199915 5120.00 + 49.311 0.999829 199924 5851.43 + 49.311 0.999854 199924 6826.67 + 49.343 0.999878 199930 8192.00 + 49.375 0.999890 199937 9102.22 + 49.375 0.999902 199937 10240.00 + 49.375 0.999915 199937 11702.86 + 49.407 0.999927 199941 13653.33 + 49.407 0.999939 199941 16384.00 + 49.439 0.999945 199942 18204.44 + 49.471 0.999951 199943 20480.00 + 49.535 0.999957 199944 23405.71 + 49.567 0.999963 199945 27306.67 + 49.599 0.999969 199946 32768.00 + 49.631 0.999973 199947 36408.89 + 49.663 0.999976 199950 40960.00 + 49.663 0.999979 199950 46811.43 + 49.663 0.999982 199950 54613.33 + 49.663 0.999985 199950 65536.00 + 49.663 0.999986 199950 72817.78 + 49.663 0.999988 199950 81920.00 + 49.663 0.999989 199950 93622.86 + 49.695 0.999991 199951 109226.67 + 49.695 0.999992 199951 131072.00 + 49.695 0.999993 199951 145635.56 + 49.695 0.999994 199951 163840.00 + 49.695 0.999995 199951 187245.71 + 49.727 0.999995 199952 218453.33 + 49.727 1.000000 199952 inf +#[Mean = 1.623, StdDeviation = 4.789] +#[Max = 49.696, Total count = 199952] +#[Buckets = 27, SubBuckets = 2048] +---------------------------------------------------------- + 299993 requests in 30.00s, 21.06MB read + Non-2xx or 3xx responses: 1 +Requests/sec: 9999.56 +Transfer/sec: 718.68KB diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/wrk/put b/src/main/java/ru/vk/itmo/test/osipovdaniil/wrk/put new file mode 100644 index 000000000..5750d27f8 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/wrk/put @@ -0,0 +1,118 @@ +./wrk -d 30 -t 1 -c 1 -R 10000 -L -s /home/sbread/Desktop/labs/HLS/2024-highload-dht/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/put.lua http://localhost:8080 +Running 30s test @ http://localhost:8080 + 1 threads and 1 connections + Thread calibration: mean lat.: 2.775ms, rate sampling interval: 19ms + Thread Stats Avg Stdev Max +/- Stdev + Latency 835.98us 0.98ms 10.77ms 94.82% + Req/Sec 10.30k 555.06 15.89k 77.74% + Latency Distribution (HdrHistogram - Recorded Latency) + 50.000% 689.00us + 75.000% 0.99ms + 90.000% 1.18ms + 99.000% 5.95ms + 99.900% 9.87ms + 99.990% 10.35ms + 99.999% 10.75ms +100.000% 10.77ms + + Detailed Percentile spectrum: + Value Percentile TotalCount 1/(1-Percentile) + + 0.035 0.000000 2 1.00 + 0.185 0.100000 20088 1.11 + 0.309 0.200000 40143 1.25 + 0.433 0.300000 60042 1.43 + 0.560 0.400000 80109 1.67 + 0.689 0.500000 100096 2.00 + 0.750 0.550000 110009 2.22 + 0.811 0.600000 120102 2.50 + 0.871 0.650000 130078 2.86 + 0.930 0.700000 140007 3.33 + 0.988 0.750000 149991 4.00 + 1.016 0.775000 154959 4.44 + 1.045 0.800000 160091 5.00 + 1.073 0.825000 165032 5.71 + 1.101 0.850000 170029 6.67 + 1.130 0.875000 175062 8.00 + 1.149 0.887500 177499 8.89 + 1.181 0.900000 179954 10.00 + 1.280 0.912500 182458 11.43 + 1.441 0.925000 184960 13.33 + 1.629 0.937500 187452 16.00 + 1.738 0.943750 188700 17.78 + 1.849 0.950000 189949 20.00 + 1.971 0.956250 191196 22.86 + 2.201 0.962500 192447 26.67 + 2.689 0.968750 193697 32.00 + 2.969 0.971875 194325 35.56 + 3.301 0.975000 194947 40.00 + 3.705 0.978125 195572 45.71 + 4.179 0.981250 196195 53.33 + 4.635 0.984375 196820 64.00 + 4.879 0.985938 197132 71.11 + 5.199 0.987500 197444 80.00 + 5.575 0.989062 197759 91.43 + 6.143 0.990625 198071 106.67 + 6.695 0.992188 198384 128.00 + 6.959 0.992969 198539 142.22 + 7.447 0.993750 198694 160.00 + 7.931 0.994531 198850 182.86 + 8.263 0.995313 199010 213.33 + 8.575 0.996094 199164 256.00 + 8.807 0.996484 199241 284.44 + 9.087 0.996875 199319 320.00 + 9.311 0.997266 199397 365.71 + 9.455 0.997656 199476 426.67 + 9.535 0.998047 199558 512.00 + 9.583 0.998242 199592 568.89 + 9.631 0.998437 199631 640.00 + 9.711 0.998633 199675 731.43 + 9.783 0.998828 199710 853.33 + 9.887 0.999023 199749 1024.00 + 9.951 0.999121 199770 1137.78 + 9.999 0.999219 199793 1280.00 + 10.023 0.999316 199808 1462.86 + 10.055 0.999414 199828 1706.67 + 10.087 0.999512 199849 2048.00 + 10.095 0.999561 199856 2275.56 + 10.119 0.999609 199869 2560.00 + 10.143 0.999658 199878 2925.71 + 10.159 0.999707 199886 3413.33 + 10.183 0.999756 199897 4096.00 + 10.191 0.999780 199901 4551.11 + 10.207 0.999805 199904 5120.00 + 10.239 0.999829 199910 5851.43 + 10.271 0.999854 199915 6826.67 + 10.319 0.999878 199920 8192.00 + 10.351 0.999890 199923 9102.22 + 10.367 0.999902 199925 10240.00 + 10.383 0.999915 199926 11702.86 + 10.407 0.999927 199930 13653.33 + 10.423 0.999939 199931 16384.00 + 10.487 0.999945 199933 18204.44 + 10.527 0.999951 199934 20480.00 + 10.583 0.999957 199935 23405.71 + 10.623 0.999963 199936 27306.67 + 10.671 0.999969 199937 32768.00 + 10.719 0.999973 199939 36408.89 + 10.719 0.999976 199939 40960.00 + 10.719 0.999979 199939 46811.43 + 10.735 0.999982 199940 54613.33 + 10.735 0.999985 199940 65536.00 + 10.751 0.999986 199941 72817.78 + 10.751 0.999988 199941 81920.00 + 10.751 0.999989 199941 93622.86 + 10.759 0.999991 199942 109226.67 + 10.759 0.999992 199942 131072.00 + 10.759 0.999993 199942 145635.56 + 10.759 0.999994 199942 163840.00 + 10.759 0.999995 199942 187245.71 + 10.775 0.999995 199943 218453.33 + 10.775 1.000000 199943 inf +#[Mean = 0.836, StdDeviation = 0.981] +#[Max = 10.768, Total count = 199943] +#[Buckets = 27, SubBuckets = 2048] +---------------------------------------------------------- + 299992 requests in 30.00s, 19.17MB read +Requests/sec: 9999.59 +Transfer/sec: 654.27KB From 02176384750c5aa102fdb638a8ee33481e542467 Mon Sep 17 00:00:00 2001 From: sbread Date: Thu, 29 Feb 2024 22:49:37 +0300 Subject: [PATCH 07/23] report --- build.gradle | 6 + .../osipovdaniil/asyncprof/delete alloc.html | 396 ++++ .../osipovdaniil/asyncprof/delete cpu.html | 1405 +++++++++++++ .../osipovdaniil/asyncprof/get alloc.html | 399 ++++ .../test/osipovdaniil/asyncprof/get cpu.html | 1102 ++++++++++ .../osipovdaniil/asyncprof/put alloc.html | 432 ++++ .../test/osipovdaniil/asyncprof/put cpu.html | 1856 +++++++++++++++++ .../ru/vk/itmo/test/osipovdaniil/report.md | 35 + .../ru/vk/itmo/test/osipovdaniil/wrk/delete | 298 +++ .../java/ru/vk/itmo/test/osipovdaniil/wrk/get | 223 ++ .../java/ru/vk/itmo/test/osipovdaniil/wrk/put | 882 ++++++++ 11 files changed, 7034 insertions(+) create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/asyncprof/delete alloc.html create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/asyncprof/delete cpu.html create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/asyncprof/get alloc.html create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/asyncprof/get cpu.html create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/asyncprof/put alloc.html create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/asyncprof/put cpu.html create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/report.md diff --git a/build.gradle b/build.gradle index a82c0105b..04e626163 100644 --- a/build.gradle +++ b/build.gradle @@ -61,3 +61,9 @@ compileJava { compileTestJava { options.compilerArgs += ["--enable-preview"] } + +run { + maxHeapSize = "128m" + jvmArgs += ["--enable-preview"] + mainClassName = 'ru.vk.itmo.test.osipovdaniil.Server' +} diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/asyncprof/delete alloc.html b/src/main/java/ru/vk/itmo/test/osipovdaniil/asyncprof/delete alloc.html new file mode 100644 index 000000000..23a852c18 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/asyncprof/delete alloc.html @@ -0,0 +1,396 @@ + + + + + + + +

Allocation profile

+
  
+
Produced by async-profiler
+ +
+

+

Matched:

+ diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/asyncprof/delete cpu.html b/src/main/java/ru/vk/itmo/test/osipovdaniil/asyncprof/delete cpu.html new file mode 100644 index 000000000..27b9382f6 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/asyncprof/delete cpu.html @@ -0,0 +1,1405 @@ + + + + + + + +

CPU profile

+
  
+
Produced by async-profiler
+ +
+

+

Matched:

+ diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/asyncprof/get alloc.html b/src/main/java/ru/vk/itmo/test/osipovdaniil/asyncprof/get alloc.html new file mode 100644 index 000000000..5a3e49d34 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/asyncprof/get alloc.html @@ -0,0 +1,399 @@ + + + + + + + +

Allocation profile

+
  
+
Produced by async-profiler
+ +
+

+

Matched:

+ diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/asyncprof/get cpu.html b/src/main/java/ru/vk/itmo/test/osipovdaniil/asyncprof/get cpu.html new file mode 100644 index 000000000..de77b0bff --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/asyncprof/get cpu.html @@ -0,0 +1,1102 @@ + + + + + + + +

CPU profile

+
  
+
Produced by async-profiler
+ +
+

+

Matched:

+ diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/asyncprof/put alloc.html b/src/main/java/ru/vk/itmo/test/osipovdaniil/asyncprof/put alloc.html new file mode 100644 index 000000000..833825da5 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/asyncprof/put alloc.html @@ -0,0 +1,432 @@ + + + + + + + +

Allocation profile

+
  
+
Produced by async-profiler
+ +
+

+

Matched:

+ diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/asyncprof/put cpu.html b/src/main/java/ru/vk/itmo/test/osipovdaniil/asyncprof/put cpu.html new file mode 100644 index 000000000..ebf8684ef --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/asyncprof/put cpu.html @@ -0,0 +1,1856 @@ + + + + + + + +

CPU profile

+
  
+
Produced by async-profiler
+ +
+

+

Matched:

+ diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/report.md b/src/main/java/ru/vk/itmo/test/osipovdaniil/report.md new file mode 100644 index 000000000..8636ecac5 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/report.md @@ -0,0 +1,35 @@ +# Отчёт по 1 заданию. + +Скрипты для теста методов лежат в папке `scripts`. Последовательные `put, get, delete`.
+`flushThresholdBytes = 2^20`
+Реализация `Dao` взята с референса. + +## wrk2 + +Собственно сразу пошёл искать точку разладки запуская +``./wrk -d 30 -t 1 -c 1 -R 18500 -L -s /home/sbread/Desktop/labs/HLS/2024-highload-dht/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/put.lua http://localhost:8080`` +с разным количеством запросов в секунду.
+Так я пришёл к константе `18500` запросов в секунду. `mean latency` было меньше секунды. +На тот момент было 80 SSTabl'ов. (выводы wrk лежат в +соответсвующей папке в файле с соответствующем названием)
+ +Однако решив перетестировать, заметил увеличение таймингов.
+Так обнаружил несколько зависимостей: +1) Скорость работы как `put` так и `get` падает с увеличением количевства SSTable'ов. +2) `get` `delete` `get`. В такой последовательности второй `get` работает быстрее первого.
+Логично ведь обновлённые данные лежат выше. + +Это было подтверждено, после сброса данных, вызовом скриптов в соотетсвующих последовательностях.
+Также было замечен стабильный экспоненциальный скачёк задержек на 75, 90 и выше персентилях. +Как будто происходит накопление нагрузки. + +## async-profiler + +Результаты в папке `asyncprof`
+ +С точки зрения cpu основные ресурсы съедает обработка запроса. +Однако есть концептуальная разница в распределнии, так `get` съедает больше ресурсов за счёт возвращения результата. + +С точки зрения аллокаций, распределение схожее, за исключением детали, что +в случае `put` и `delete` память аллоцируется на запись, +а в случае `get` на возвращения результата diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/wrk/delete b/src/main/java/ru/vk/itmo/test/osipovdaniil/wrk/delete index e276951b9..65790d7b9 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/wrk/delete +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/wrk/delete @@ -116,3 +116,301 @@ Running 30s test @ http://localhost:8080 299973 requests in 30.00s, 19.45MB read Requests/sec: 9999.19 Transfer/sec: 664.01KB + +-------------------------------------------------------------------------------------------- + +# 1 thread, 1 connection, duration 30 sec, rate 18500 + +./wrk -d 30 -t 1 -c 1 -R 18500 -L -s /home/sbread/Desktop/labs/HLS/2024-highload-dht/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/delete.lua http://localhost:8080 +Running 30s test @ http://localhost:8080 + 1 threads and 1 connections + Thread calibration: mean lat.: 1718.670ms, rate sampling interval: 5431ms + Thread Stats Avg Stdev Max +/- Stdev + Latency 4.43s 317.02ms 4.92s 79.95% + Req/Sec 16.62k 2.16k 19.02k 33.33% + Latency Distribution (HdrHistogram - Recorded Latency) + 50.000% 4.44s + 75.000% 4.65s + 90.000% 4.79s + 99.000% 4.91s + 99.900% 4.92s + 99.990% 4.92s + 99.999% 4.92s +100.000% 4.92s + + Detailed Percentile spectrum: + Value Percentile TotalCount 1/(1-Percentile) + + 3045.375 0.000000 34 1.00 + 4169.727 0.100000 34626 1.11 + 4308.991 0.200000 72462 1.25 + 4345.855 0.300000 106217 1.43 + 4395.007 0.400000 141604 1.67 + 4435.967 0.500000 176742 2.00 + 4472.831 0.550000 191917 2.22 + 4513.791 0.600000 209812 2.50 + 4538.367 0.650000 225056 2.86 + 4562.943 0.700000 242151 3.33 + 4653.055 0.750000 259178 4.00 + 4681.727 0.775000 268357 4.44 + 4698.111 0.800000 278536 5.00 + 4710.399 0.825000 288428 5.71 + 4722.687 0.850000 294504 6.67 + 4747.263 0.875000 302878 8.00 + 4767.743 0.887500 306952 8.89 + 4788.223 0.900000 311618 10.00 + 4800.511 0.912500 315442 11.43 + 4812.799 0.925000 320054 13.33 + 4825.087 0.937500 324601 16.00 + 4833.279 0.943750 326078 17.78 + 4845.567 0.950000 329137 20.00 + 4849.663 0.956250 330327 22.86 + 4861.951 0.962500 333514 26.67 + 4870.143 0.968750 335742 32.00 + 4870.143 0.971875 335742 35.56 + 4878.335 0.975000 337249 40.00 + 4882.431 0.978125 337970 45.71 + 4890.623 0.981250 339387 53.33 + 4894.719 0.984375 340169 64.00 + 4898.815 0.985938 340933 71.11 + 4902.911 0.987500 341794 80.00 + 4902.911 0.989062 341794 91.43 + 4907.007 0.990625 342555 106.67 + 4911.103 0.992188 343247 128.00 + 4911.103 0.992969 343247 142.22 + 4911.103 0.993750 343247 160.00 + 4915.199 0.994531 345073 182.86 + 4915.199 0.995313 345073 213.33 + 4915.199 0.996094 345073 256.00 + 4915.199 0.996484 345073 284.44 + 4915.199 0.996875 345073 320.00 + 4915.199 0.997266 345073 365.71 + 4915.199 0.997656 345073 426.67 + 4915.199 0.998047 345073 512.00 + 4915.199 0.998242 345073 568.89 + 4915.199 0.998437 345073 640.00 + 4915.199 0.998633 345073 731.43 + 4915.199 0.998828 345073 853.33 + 4915.199 0.999023 345073 1024.00 + 4919.295 0.999121 345405 1137.78 + 4919.295 1.000000 345405 inf +#[Mean = 4430.304, StdDeviation = 317.022] +#[Max = 4915.200, Total count = 345405] +#[Buckets = 27, SubBuckets = 2048] +---------------------------------------------------------- + 474199 requests in 30.00s, 30.75MB read +Requests/sec: 15806.79 +Transfer/sec: 1.03MB + +-------------------------------------------------------------------------- + +# 1 thread, 1 connection, duration 30 sec, rate 18500 +# delete after delete + +./wrk -d 30 -t 1 -c 1 -R 18500 -L -s /home/sbread/Desktop/labs/HLS/2024-highload-dht/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/delete.lua http://localhost:8080 +Running 30s test @ http://localhost:8080 + 1 threads and 1 connections + Thread calibration: mean lat.: 14.532ms, rate sampling interval: 95ms + Thread Stats Avg Stdev Max +/- Stdev + Latency 1.27s 985.90ms 2.63s 49.20% + Req/Sec 16.54k 3.90k 23.36k 57.14% + Latency Distribution (HdrHistogram - Recorded Latency) + 50.000% 1.16s + 75.000% 2.32s + 90.000% 2.49s + 99.000% 2.62s + 99.900% 2.63s + 99.990% 2.63s + 99.999% 2.63s +100.000% 2.63s + + Detailed Percentile spectrum: + Value Percentile TotalCount 1/(1-Percentile) + + 0.033 0.000000 2 1.00 + 7.859 0.100000 32905 1.11 + 200.063 0.200000 65799 1.25 + 387.583 0.300000 98750 1.43 + 643.583 0.400000 131873 1.67 + 1162.239 0.500000 164496 2.00 + 1632.255 0.550000 180958 2.22 + 1861.631 0.600000 197408 2.50 + 2134.015 0.650000 214204 2.86 + 2230.271 0.700000 230445 3.33 + 2318.335 0.750000 246750 4.00 + 2365.439 0.775000 255013 4.44 + 2387.967 0.800000 263256 5.00 + 2410.495 0.825000 271504 5.71 + 2447.359 0.850000 279681 6.67 + 2461.695 0.875000 288176 8.00 + 2467.839 0.887500 291983 8.89 + 2488.319 0.900000 296092 10.00 + 2498.559 0.912500 300774 11.43 + 2510.847 0.925000 304571 13.33 + 2535.423 0.937500 308441 16.00 + 2549.759 0.943750 310676 17.78 + 2562.047 0.950000 313296 20.00 + 2570.239 0.956250 314699 22.86 + 2580.479 0.962500 316814 26.67 + 2592.767 0.968750 318832 32.00 + 2596.863 0.971875 319901 35.56 + 2603.007 0.975000 321891 40.00 + 2603.007 0.978125 321891 45.71 + 2607.103 0.981250 323000 53.33 + 2609.151 0.984375 324069 64.00 + 2611.199 0.985938 324471 71.11 + 2615.295 0.987500 325563 80.00 + 2615.295 0.989062 325563 91.43 + 2617.343 0.990625 325986 106.67 + 2621.439 0.992188 326638 128.00 + 2623.487 0.992969 327000 142.22 + 2623.487 0.993750 327000 160.00 + 2625.535 0.994531 327793 182.86 + 2625.535 0.995313 327793 213.33 + 2625.535 0.996094 327793 256.00 + 2627.583 0.996484 328177 284.44 + 2627.583 0.996875 328177 320.00 + 2627.583 0.997266 328177 365.71 + 2629.631 0.997656 328616 426.67 + 2629.631 0.998047 328616 512.00 + 2629.631 0.998242 328616 568.89 + 2629.631 0.998437 328616 640.00 + 2629.631 0.998633 328616 731.43 + 2629.631 0.998828 328616 853.33 + 2631.679 0.999023 328981 1024.00 + 2631.679 1.000000 328981 inf +#[Mean = 1274.320, StdDeviation = 985.896] +#[Max = 2629.632, Total count = 328981] +#[Buckets = 27, SubBuckets = 2048] +---------------------------------------------------------- + 513996 requests in 30.00s, 33.33MB read +Requests/sec: 17133.45 +Transfer/sec: 1.11MB + +-------------------------------------------------------------------------- + +# 1 thread, 1 connection, duration 30 sec, rate 18500 +# after 3 put and 1 get + +./wrk -d 30 -t 1 -c 1 -R 18500 -L -s /home/sbread/Desktop/labs/HLS/2024-highload-dht/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/delete.lua http://localhost:8080 +Running 30s test @ http://localhost:8080 + 1 threads and 1 connections + Thread calibration: mean lat.: 5.954ms, rate sampling interval: 42ms + Thread Stats Avg Stdev Max +/- Stdev + Latency 2.85ms 6.67ms 42.53ms 93.09% + Req/Sec 18.74k 1.31k 23.22k 85.92% + Latency Distribution (HdrHistogram - Recorded Latency) + 50.000% 0.91ms + 75.000% 1.47ms + 90.000% 5.49ms + 99.000% 38.30ms + 99.900% 41.73ms + 99.990% 42.40ms + 99.999% 42.53ms +100.000% 42.56ms + + Detailed Percentile spectrum: + Value Percentile TotalCount 1/(1-Percentile) + + 0.031 0.000000 1 1.00 + 0.239 0.100000 37016 1.11 + 0.417 0.200000 74021 1.25 + 0.586 0.300000 111066 1.43 + 0.757 0.400000 148122 1.67 + 0.910 0.500000 185169 2.00 + 0.984 0.550000 203570 2.22 + 1.056 0.600000 222069 2.50 + 1.119 0.650000 240435 2.86 + 1.248 0.700000 258940 3.33 + 1.474 0.750000 277462 4.00 + 1.631 0.775000 286675 4.44 + 1.949 0.800000 295925 5.00 + 2.395 0.825000 305179 5.71 + 3.173 0.850000 314414 6.67 + 4.223 0.875000 323664 8.00 + 4.799 0.887500 328289 8.89 + 5.495 0.900000 332917 10.00 + 6.347 0.912500 337532 11.43 + 7.919 0.925000 342146 13.33 + 11.671 0.937500 346773 16.00 + 13.423 0.943750 349080 17.78 + 14.895 0.950000 351396 20.00 + 16.959 0.956250 353713 22.86 + 21.103 0.962500 356035 26.67 + 25.743 0.968750 358333 32.00 + 27.807 0.971875 359488 35.56 + 29.743 0.975000 360645 40.00 + 32.239 0.978125 361798 45.71 + 34.687 0.981250 362965 53.33 + 36.063 0.984375 364130 64.00 + 36.415 0.985938 364709 71.11 + 36.767 0.987500 365278 80.00 + 37.887 0.989062 365843 91.43 + 38.623 0.990625 366434 106.67 + 39.487 0.992188 367062 128.00 + 39.679 0.992969 367293 142.22 + 39.935 0.993750 367610 160.00 + 40.159 0.994531 367891 182.86 + 40.287 0.995313 368159 213.33 + 40.383 0.996094 368453 256.00 + 40.447 0.996484 368614 284.44 + 40.575 0.996875 368734 320.00 + 40.895 0.997266 368888 365.71 + 41.055 0.997656 369034 426.67 + 41.279 0.998047 369175 512.00 + 41.375 0.998242 369236 568.89 + 41.535 0.998437 369336 640.00 + 41.631 0.998633 369405 731.43 + 41.695 0.998828 369486 853.33 + 41.759 0.999023 369563 1024.00 + 41.759 0.999121 369563 1137.78 + 41.791 0.999219 369610 1280.00 + 41.823 0.999316 369638 1462.86 + 41.887 0.999414 369692 1706.67 + 41.919 0.999512 369713 2048.00 + 41.951 0.999561 369735 2275.56 + 41.983 0.999609 369754 2560.00 + 42.015 0.999658 369766 2925.71 + 42.047 0.999707 369794 3413.33 + 42.079 0.999756 369798 4096.00 + 42.143 0.999780 369808 4551.11 + 42.207 0.999805 369817 5120.00 + 42.271 0.999829 369827 5851.43 + 42.303 0.999854 369836 6826.67 + 42.335 0.999878 369841 8192.00 + 42.367 0.999890 369848 9102.22 + 42.399 0.999902 369854 10240.00 + 42.431 0.999915 369860 11702.86 + 42.431 0.999927 369860 13653.33 + 42.463 0.999939 369867 16384.00 + 42.463 0.999945 369867 18204.44 + 42.495 0.999951 369875 20480.00 + 42.495 0.999957 369875 23405.71 + 42.495 0.999963 369875 27306.67 + 42.495 0.999969 369875 32768.00 + 42.527 0.999973 369885 36408.89 + 42.527 0.999976 369885 40960.00 + 42.527 0.999979 369885 46811.43 + 42.527 0.999982 369885 54613.33 + 42.527 0.999985 369885 65536.00 + 42.527 0.999986 369885 72817.78 + 42.527 0.999988 369885 81920.00 + 42.527 0.999989 369885 93622.86 + 42.527 0.999991 369885 109226.67 + 42.527 0.999992 369885 131072.00 + 42.527 0.999993 369885 145635.56 + 42.527 0.999994 369885 163840.00 + 42.527 0.999995 369885 187245.71 + 42.527 0.999995 369885 218453.33 + 42.527 0.999996 369885 262144.00 + 42.527 0.999997 369885 291271.11 + 42.527 0.999997 369885 327680.00 + 42.559 0.999997 369886 374491.43 + 42.559 1.000000 369886 inf +#[Mean = 2.850, StdDeviation = 6.667] +#[Max = 42.528, Total count = 369886] +#[Buckets = 27, SubBuckets = 2048] +---------------------------------------------------------- + 554966 requests in 30.00s, 35.99MB read +Requests/sec: 18499.05 +Transfer/sec: 1.20MB diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/wrk/get b/src/main/java/ru/vk/itmo/test/osipovdaniil/wrk/get index 2bba35360..699659f99 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/wrk/get +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/wrk/get @@ -117,3 +117,226 @@ Running 30s test @ http://localhost:8080 Non-2xx or 3xx responses: 1 Requests/sec: 9999.56 Transfer/sec: 718.68KB + +-------------------------------------------------------------------------------------------- + +# 1 thread, 1 connection, duration 30 sec, rate 18500 + +./wrk -d 30 -t 1 -c 1 -R 18500 -L -s /home/sbread/Desktop/labs/HLS/2024-highload-dht/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/get.lua http://localhost:8080 +Running 30s test @ http://localhost:8080 + 1 threads and 1 connections + Thread calibration: mean lat.: 1858.328ms, rate sampling interval: 6213ms + Thread Stats Avg Stdev Max +/- Stdev + Latency 2.67s 337.09ms 3.12s 63.34% + Req/Sec 18.81k 1.23k 20.24k 33.33% + Latency Distribution (HdrHistogram - Recorded Latency) + 50.000% 2.77s + 75.000% 2.94s + 90.000% 3.08s + 99.000% 3.12s + 99.900% 3.12s + 99.990% 3.12s + 99.999% 3.12s +100.000% 3.12s + + Detailed Percentile spectrum: + Value Percentile TotalCount 1/(1-Percentile) + + 2019.327 0.000000 90 1.00 + 2125.823 0.100000 37035 1.11 + 2342.911 0.200000 74148 1.25 + 2476.031 0.300000 111257 1.43 + 2600.959 0.400000 147938 1.67 + 2766.847 0.500000 184959 2.00 + 2828.287 0.550000 203602 2.22 + 2877.439 0.600000 223905 2.50 + 2902.015 0.650000 244018 2.86 + 2914.303 0.700000 260273 3.33 + 2940.927 0.750000 277178 4.00 + 2955.263 0.775000 286554 4.44 + 2965.503 0.800000 296617 5.00 + 3002.367 0.825000 305141 5.71 + 3039.231 0.850000 315743 6.67 + 3049.471 0.875000 323496 8.00 + 3063.807 0.887500 328210 8.89 + 3084.287 0.900000 333224 10.00 + 3088.383 0.912500 341082 11.43 + 3090.431 0.925000 344401 13.33 + 3092.479 0.937500 347105 16.00 + 3094.527 0.943750 351326 17.78 + 3094.527 0.950000 351326 20.00 + 3096.575 0.956250 353918 22.86 + 3098.623 0.962500 356241 26.67 + 3100.671 0.968750 358086 32.00 + 3102.719 0.971875 360300 35.56 + 3104.767 0.975000 362289 40.00 + 3104.767 0.978125 362289 45.71 + 3106.815 0.981250 363618 53.33 + 3108.863 0.984375 364409 64.00 + 3108.863 0.985938 364409 71.11 + 3110.911 0.987500 365103 80.00 + 3112.959 0.989062 365756 91.43 + 3115.007 0.990625 366424 106.67 + 3117.055 0.992188 368156 128.00 + 3117.055 0.992969 368156 142.22 + 3117.055 0.993750 368156 160.00 + 3117.055 0.994531 368156 182.86 + 3117.055 0.995313 368156 213.33 + 3117.055 0.996094 368156 256.00 + 3119.103 0.996484 369078 284.44 + 3119.103 0.996875 369078 320.00 + 3119.103 0.997266 369078 365.71 + 3119.103 0.997656 369078 426.67 + 3119.103 0.998047 369078 512.00 + 3119.103 0.998242 369078 568.89 + 3119.103 0.998437 369078 640.00 + 3119.103 0.998633 369078 731.43 + 3121.151 0.998828 369551 853.33 + 3121.151 0.999023 369551 1024.00 + 3121.151 0.999121 369551 1137.78 + 3121.151 0.999219 369551 1280.00 + 3121.151 0.999316 369551 1462.86 + 3121.151 0.999414 369551 1706.67 + 3121.151 0.999512 369551 2048.00 + 3121.151 0.999561 369551 2275.56 + 3121.151 0.999609 369551 2560.00 + 3121.151 0.999658 369551 2925.71 + 3121.151 0.999707 369551 3413.33 + 3121.151 0.999756 369551 4096.00 + 3121.151 0.999780 369551 4551.11 + 3121.151 0.999805 369551 5120.00 + 3121.151 0.999829 369551 5851.43 + 3121.151 0.999854 369551 6826.67 + 3121.151 0.999878 369551 8192.00 + 3121.151 0.999890 369551 9102.22 + 3121.151 0.999902 369551 10240.00 + 3121.151 0.999915 369551 11702.86 + 3121.151 0.999927 369551 13653.33 + 3121.151 0.999939 369551 16384.00 + 3121.151 0.999945 369551 18204.44 + 3121.151 0.999951 369551 20480.00 + 3121.151 0.999957 369551 23405.71 + 3121.151 0.999963 369551 27306.67 + 3121.151 0.999969 369551 32768.00 + 3121.151 0.999973 369551 36408.89 + 3121.151 0.999976 369551 40960.00 + 3121.151 0.999979 369551 46811.43 + 3121.151 0.999982 369551 54613.33 + 3121.151 0.999985 369551 65536.00 + 3121.151 0.999986 369551 72817.78 + 3121.151 0.999988 369551 81920.00 + 3121.151 0.999989 369551 93622.86 + 3121.151 0.999991 369551 109226.67 + 3123.199 0.999992 369554 131072.00 + 3123.199 1.000000 369554 inf +#[Mean = 2668.860, StdDeviation = 337.093] +#[Max = 3121.152, Total count = 369554] +#[Buckets = 27, SubBuckets = 2048] +---------------------------------------------------------- + 497244 requests in 30.00s, 34.90MB read + Non-2xx or 3xx responses: 16381 +Requests/sec: 16574.95 +Transfer/sec: 1.16MB + +-------------------------------------------------------------------------------------------- + +# 1 thread, 1 connection, duration 30 sec, rate 18500 + +./wrk -d 30 -t 1 -c 1 -R 18500 -L -s /home/sbread/Desktop/labs/HLS/2024-highload-dht/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/get.lua http://localhost:8080 +Running 30s test @ http://localhost:8080 + 1 threads and 1 connections + Thread calibration: mean lat.: 509.177ms, rate sampling interval: 1292ms + Thread Stats Avg Stdev Max +/- Stdev + Latency 63.99ms 94.98ms 374.78ms 82.67% + Req/Sec 18.87k 643.66 20.22k 73.33% + Latency Distribution (HdrHistogram - Recorded Latency) + 50.000% 7.36ms + 75.000% 109.63ms + 90.000% 228.99ms + 99.000% 354.05ms + 99.900% 373.25ms + 99.990% 374.78ms + 99.999% 375.04ms +100.000% 375.04ms + + Detailed Percentile spectrum: + Value Percentile TotalCount 1/(1-Percentile) + + 0.033 0.000000 4 1.00 + 0.505 0.100000 37778 1.11 + 0.894 0.200000 75447 1.25 + 1.273 0.300000 113114 1.43 + 2.597 0.400000 150747 1.67 + 7.355 0.500000 188426 2.00 + 11.919 0.550000 207253 2.22 + 24.303 0.600000 226110 2.50 + 45.439 0.650000 245272 2.86 + 70.335 0.700000 263790 3.33 + 109.631 0.750000 282619 4.00 + 140.543 0.775000 292078 4.44 + 147.967 0.800000 301476 5.00 + 157.439 0.825000 310911 5.71 + 170.239 0.850000 320424 6.67 + 177.535 0.875000 329788 8.00 + 210.687 0.887500 334446 8.89 + 228.991 0.900000 339145 10.00 + 239.615 0.912500 343929 11.43 + 250.239 0.925000 348670 13.33 + 257.407 0.937500 353295 16.00 + 270.079 0.943750 355666 17.78 + 282.623 0.950000 357984 20.00 + 295.167 0.956250 360363 22.86 + 305.151 0.962500 362733 26.67 + 308.223 0.968750 365120 32.00 + 315.135 0.971875 366237 35.56 + 323.327 0.975000 367451 40.00 + 327.679 0.978125 368598 45.71 + 335.103 0.981250 369765 53.33 + 343.295 0.984375 370952 64.00 + 347.391 0.985938 371545 71.11 + 351.487 0.987500 372134 80.00 + 353.023 0.989062 372721 91.43 + 354.559 0.990625 373359 106.67 + 357.119 0.992188 373885 128.00 + 359.423 0.992969 374195 142.22 + 360.959 0.993750 374492 160.00 + 363.007 0.994531 374804 182.86 + 365.055 0.995313 375085 213.33 + 366.591 0.996094 375382 256.00 + 367.359 0.996484 375510 284.44 + 368.383 0.996875 375667 320.00 + 369.407 0.997266 375818 365.71 + 370.431 0.997656 375957 426.67 + 371.455 0.998047 376099 512.00 + 371.967 0.998242 376170 568.89 + 372.479 0.998437 376253 640.00 + 372.991 0.998633 376427 731.43 + 372.991 0.998828 376427 853.33 + 373.247 0.999023 376553 1024.00 + 373.247 0.999121 376553 1137.78 + 373.247 0.999219 376553 1280.00 + 373.503 0.999316 376602 1462.86 + 373.759 0.999414 376648 1706.67 + 373.759 0.999512 376648 2048.00 + 374.015 0.999561 376686 2275.56 + 374.015 0.999609 376686 2560.00 + 374.271 0.999658 376719 2925.71 + 374.271 0.999707 376719 3413.33 + 374.527 0.999756 376753 4096.00 + 374.527 0.999780 376753 4551.11 + 374.527 0.999805 376753 5120.00 + 374.783 0.999829 376789 5851.43 + 374.783 0.999854 376789 6826.67 + 374.783 0.999878 376789 8192.00 + 374.783 0.999890 376789 9102.22 + 374.783 0.999902 376789 10240.00 + 375.039 0.999915 376823 11702.86 + 375.039 1.000000 376823 inf +#[Mean = 63.987, StdDeviation = 94.984] +#[Max = 374.784, Total count = 376823] +#[Buckets = 27, SubBuckets = 2048] +---------------------------------------------------------- + 554983 requests in 30.00s, 39.05MB read + Non-2xx or 3xx responses: 1 +Requests/sec: 18499.12 +Transfer/sec: 1.30MB diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/wrk/put b/src/main/java/ru/vk/itmo/test/osipovdaniil/wrk/put index 5750d27f8..0646324a6 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/wrk/put +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/wrk/put @@ -1,3 +1,5 @@ +# 1 thread, 1 connection, duration 30 sec, rate 10000 + ./wrk -d 30 -t 1 -c 1 -R 10000 -L -s /home/sbread/Desktop/labs/HLS/2024-highload-dht/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/put.lua http://localhost:8080 Running 30s test @ http://localhost:8080 1 threads and 1 connections @@ -116,3 +118,883 @@ Running 30s test @ http://localhost:8080 299992 requests in 30.00s, 19.17MB read Requests/sec: 9999.59 Transfer/sec: 654.27KB + +------------------------------------------------------------------------------------------------------------------ + +# 1 thread, 1 connection, duration 30 sec, rate 50000 + +./wrk -d 30 -t 1 -c 1 -R 50000 -L -s /home/sbread/Desktop/labs/HLS/2024-highload-dht/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/put.lua http://localhost:8080 +Running 30s test @ http://localhost:8080 + 1 threads and 1 connections + Thread calibration: mean lat.: 3496.575ms, rate sampling interval: 12894ms + Thread Stats Avg Stdev Max +/- Stdev + Latency 13.12s 3.49s 19.40s 58.15% + Req/Sec 19.96k 0.00 19.97k 0.00% + Latency Distribution (HdrHistogram - Recorded Latency) + 50.000% 12.94s + 75.000% 16.20s + 90.000% 18.09s + 99.000% 19.28s + 99.900% 19.40s + 99.990% 19.42s + 99.999% 19.42s +100.000% 19.42s + + Detailed Percentile spectrum: + Value Percentile TotalCount 1/(1-Percentile) + + 7184.383 0.000000 89 1.00 + 8380.415 0.100000 39032 1.11 + 9584.639 0.200000 77789 1.25 + 10764.287 0.300000 116723 1.43 + 11886.591 0.400000 155612 1.67 + 12935.167 0.500000 194597 2.00 + 13508.607 0.550000 213961 2.22 + 14114.815 0.600000 233516 2.50 + 14753.791 0.650000 252689 2.86 + 15548.415 0.700000 272317 3.33 + 16203.775 0.750000 291669 4.00 + 16482.303 0.775000 301379 4.44 + 16809.983 0.800000 311197 5.00 + 17104.895 0.825000 320766 5.71 + 17416.191 0.850000 330751 6.67 + 17711.103 0.875000 340616 8.00 + 17858.559 0.887500 345492 8.89 + 18087.935 0.900000 350094 10.00 + 18251.775 0.912500 354997 11.43 + 18399.231 0.925000 359970 13.33 + 18563.071 0.937500 364713 16.00 + 18628.607 0.943750 366993 17.78 + 18710.527 0.950000 369671 20.00 + 18792.447 0.956250 372079 22.86 + 18857.983 0.962500 374368 26.67 + 18972.671 0.968750 376793 32.00 + 19021.823 0.971875 378101 35.56 + 19087.359 0.975000 379659 40.00 + 19120.127 0.978125 380805 45.71 + 19152.895 0.981250 381584 53.33 + 19185.663 0.984375 382683 64.00 + 19202.047 0.985938 383299 71.11 + 19234.815 0.987500 384118 80.00 + 19267.583 0.989062 384727 91.43 + 19283.967 0.990625 385195 106.67 + 19316.735 0.992188 386117 128.00 + 19316.735 0.992969 386117 142.22 + 19349.503 0.993750 386666 160.00 + 19349.503 0.994531 386666 182.86 + 19365.887 0.995313 387356 213.33 + 19365.887 0.996094 387356 256.00 + 19382.271 0.996484 388038 284.44 + 19382.271 0.996875 388038 320.00 + 19382.271 0.997266 388038 365.71 + 19382.271 0.997656 388038 426.67 + 19382.271 0.998047 388038 512.00 + 19398.655 0.998242 388681 568.89 + 19398.655 0.998437 388681 640.00 + 19398.655 0.998633 388681 731.43 + 19398.655 0.998828 388681 853.33 + 19398.655 0.999023 388681 1024.00 + 19398.655 0.999121 388681 1137.78 + 19398.655 0.999219 388681 1280.00 + 19398.655 0.999316 388681 1462.86 + 19398.655 0.999414 388681 1706.67 + 19398.655 0.999512 388681 2048.00 + 19398.655 0.999561 388681 2275.56 + 19398.655 0.999609 388681 2560.00 + 19398.655 0.999658 388681 2925.71 + 19398.655 0.999707 388681 3413.33 + 19398.655 0.999756 388681 4096.00 + 19398.655 0.999780 388681 4551.11 + 19398.655 0.999805 388681 5120.00 + 19398.655 0.999829 388681 5851.43 + 19398.655 0.999854 388681 6826.67 + 19415.039 0.999878 388737 8192.00 + 19415.039 1.000000 388737 inf +#[Mean = 13123.387, StdDeviation = 3485.691] +#[Max = 19398.656, Total count = 388737] +#[Buckets = 27, SubBuckets = 2048] +---------------------------------------------------------- + 529969 requests in 30.00s, 33.86MB read +Requests/sec: 17665.69 +Transfer/sec: 1.13MB + +------------------------------------------------------------------------- + +# 1 thread, 1 connection, duration 30 sec, rate 25000 + +./wrk -d 30 -t 1 -c 1 -R 25000 -L -s /home/sbread/Desktop/labs/HLS/2024-highload-dht/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/put.lua http://localhost:8080 +Running 30s test @ http://localhost:8080 + 1 threads and 1 connections + Thread calibration: mean lat.: 1856.660ms, rate sampling interval: 5730ms + Thread Stats Avg Stdev Max +/- Stdev + Latency 7.57s 1.66s 9.85s 62.01% + Req/Sec 16.74k 2.18k 18.54k 66.67% + Latency Distribution (HdrHistogram - Recorded Latency) + 50.000% 7.59s + 75.000% 9.09s + 90.000% 9.56s + 99.000% 9.83s + 99.900% 9.85s + 99.990% 9.86s + 99.999% 9.86s +100.000% 9.86s + + Detailed Percentile spectrum: + Value Percentile TotalCount 1/(1-Percentile) + + 3657.727 0.000000 15 1.00 + 5197.823 0.100000 34497 1.11 + 6041.599 0.200000 69098 1.25 + 6684.671 0.300000 103555 1.43 + 7151.615 0.400000 138029 1.67 + 7589.887 0.500000 172425 2.00 + 8097.791 0.550000 189669 2.22 + 8462.335 0.600000 207125 2.50 + 8798.207 0.650000 224814 2.86 + 8937.471 0.700000 241642 3.33 + 9093.119 0.750000 258765 4.00 + 9166.847 0.775000 267800 4.44 + 9240.575 0.800000 275985 5.00 + 9322.495 0.825000 284572 5.71 + 9388.031 0.850000 294340 6.67 + 9469.951 0.875000 301867 8.00 + 9519.103 0.887500 306588 8.89 + 9560.063 0.900000 311647 10.00 + 9584.639 0.912500 315517 11.43 + 9609.215 0.925000 320190 13.33 + 9633.791 0.937500 323435 16.00 + 9650.175 0.943750 325672 17.78 + 9666.559 0.950000 328204 20.00 + 9682.943 0.956250 330223 22.86 + 9707.519 0.962500 332329 26.67 + 9732.095 0.968750 334109 32.00 + 9748.479 0.971875 335575 35.56 + 9764.863 0.975000 336819 40.00 + 9773.055 0.978125 337578 45.71 + 9789.439 0.981250 338845 53.33 + 9797.631 0.984375 339529 64.00 + 9814.015 0.985938 340241 71.11 + 9822.207 0.987500 340787 80.00 + 9830.399 0.989062 341492 91.43 + 9838.591 0.990625 342890 106.67 + 9838.591 0.992188 342890 128.00 + 9838.591 0.992969 342890 142.22 + 9838.591 0.993750 342890 160.00 + 9846.783 0.994531 343646 182.86 + 9846.783 0.995313 343646 213.33 + 9846.783 0.996094 343646 256.00 + 9846.783 0.996484 343646 284.44 + 9854.975 0.996875 344515 320.00 + 9854.975 0.997266 344515 365.71 + 9854.975 0.997656 344515 426.67 + 9854.975 0.998047 344515 512.00 + 9854.975 0.998242 344515 568.89 + 9854.975 0.998437 344515 640.00 + 9854.975 0.998633 344515 731.43 + 9854.975 0.998828 344515 853.33 + 9854.975 0.999023 344515 1024.00 + 9863.167 0.999121 344821 1137.78 + 9863.167 1.000000 344821 inf +#[Mean = 7570.582, StdDeviation = 1664.704] +#[Max = 9854.976, Total count = 344821] +#[Buckets = 27, SubBuckets = 2048] +---------------------------------------------------------- + 503531 requests in 30.00s, 32.17MB read +Requests/sec: 16784.59 +Transfer/sec: 1.07MB + +-------------------------------------------------------------------------------------------- + +# 1 thread, 1 connection, duration 30 sec, rate 17500 + +./wrk -d 30 -t 1 -c 1 -R 17500 -L -s /home/sbread/Desktop/labs/HLS/2024-highload-dht/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/put.lua http://localhost:8080 +Running 30s test @ http://localhost:8080 + 1 threads and 1 connections + Thread calibration: mean lat.: 94.674ms, rate sampling interval: 571ms + Thread Stats Avg Stdev Max +/- Stdev + Latency 474.06ms 717.05ms 2.53s 86.69% + Req/Sec 15.31k 3.05k 19.05k 74.29% + Latency Distribution (HdrHistogram - Recorded Latency) + 50.000% 2.07ms + 75.000% 946.17ms + 90.000% 1.53s + 99.000% 2.53s + 99.900% 2.53s + 99.990% 2.53s + 99.999% 2.53s +100.000% 2.53s + + Detailed Percentile spectrum: + Value Percentile TotalCount 1/(1-Percentile) + + 0.033 0.000000 2 1.00 + 0.323 0.100000 30675 1.11 + 0.592 0.200000 61284 1.25 + 0.824 0.300000 91891 1.43 + 1.038 0.400000 122416 1.67 + 2.067 0.500000 152957 2.00 + 8.471 0.550000 168260 2.22 + 124.095 0.600000 183546 2.50 + 470.527 0.650000 198841 2.86 + 748.543 0.700000 214265 3.33 + 946.175 0.750000 229479 4.00 + 954.367 0.775000 237118 4.44 + 973.823 0.800000 244764 5.00 + 1048.575 0.825000 252409 5.71 + 1106.943 0.850000 260131 6.67 + 1275.903 0.875000 267680 8.00 + 1401.855 0.887500 271497 8.89 + 1529.855 0.900000 275323 10.00 + 1723.391 0.912500 279143 11.43 + 1936.383 0.925000 282975 13.33 + 2144.255 0.937500 286787 16.00 + 2207.743 0.943750 288716 17.78 + 2285.567 0.950000 290632 20.00 + 2383.871 0.956250 292545 22.86 + 2418.687 0.962500 294847 26.67 + 2467.839 0.968750 296370 32.00 + 2500.607 0.971875 297358 35.56 + 2516.991 0.975000 298853 40.00 + 2519.039 0.978125 299987 45.71 + 2521.087 0.981250 301236 53.33 + 2521.087 0.984375 301236 64.00 + 2523.135 0.985938 302454 71.11 + 2523.135 0.987500 302454 80.00 + 2525.183 0.989062 303538 91.43 + 2525.183 0.990625 303538 106.67 + 2525.183 0.992188 303538 128.00 + 2527.231 0.992969 304984 142.22 + 2527.231 0.993750 304984 160.00 + 2527.231 0.994531 304984 182.86 + 2527.231 0.995313 304984 213.33 + 2527.231 0.996094 304984 256.00 + 2527.231 0.996484 304984 284.44 + 2527.231 0.996875 304984 320.00 + 2529.279 0.997266 305325 365.71 + 2529.279 0.997656 305325 426.67 + 2529.279 0.998047 305325 512.00 + 2531.327 0.998242 305905 568.89 + 2531.327 1.000000 305905 inf +#[Mean = 474.061, StdDeviation = 717.048] +#[Max = 2529.280, Total count = 305905] +#[Buckets = 27, SubBuckets = 2048] +---------------------------------------------------------- + 480976 requests in 30.00s, 30.73MB read +Requests/sec: 16032.69 +Transfer/sec: 1.02MB + + +-------------------------------------------------------------------------------------------- + +# 1 thread, 1 connection, duration 30 sec, rate 21000 + +./wrk -d 30 -t 1 -c 1 -R 21000 -L -s /home/sbread/Desktop/labs/HLS/2024-highload-dht/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/put.lua http://localhost:8080 +Running 30s test @ http://localhost:8080 + 1 threads and 1 connections + Thread calibration: mean lat.: 1918.529ms, rate sampling interval: 6504ms + Thread Stats Avg Stdev Max +/- Stdev + Latency 7.47s 2.38s 11.66s 50.57% + Req/Sec 12.72k 1.14k 14.28k 33.33% + Latency Distribution (HdrHistogram - Recorded Latency) + 50.000% 7.32s + 75.000% 9.81s + 90.000% 10.80s + 99.000% 11.55s + 99.900% 11.66s + 99.990% 11.67s + 99.999% 11.67s +100.000% 11.67s + + Detailed Percentile spectrum: + Value Percentile TotalCount 1/(1-Percentile) + + 3796.991 0.000000 2 1.00 + 4562.943 0.100000 25538 1.11 + 5013.503 0.200000 51308 1.25 + 5316.607 0.300000 76531 1.43 + 6365.183 0.400000 101954 1.67 + 7319.551 0.500000 127377 2.00 + 7860.223 0.550000 140148 2.22 + 8085.503 0.600000 152936 2.50 + 8658.943 0.650000 165681 2.86 + 9289.727 0.700000 178423 3.33 + 9814.015 0.750000 191242 4.00 + 10190.847 0.775000 197541 4.44 + 10321.919 0.800000 204144 5.00 + 10346.495 0.825000 210919 5.71 + 10371.071 0.850000 217920 6.67 + 10493.951 0.875000 222924 8.00 + 10657.791 0.887500 226256 8.89 + 10797.055 0.900000 229280 10.00 + 10878.975 0.912500 232499 11.43 + 10911.743 0.925000 236066 13.33 + 11026.431 0.937500 238989 16.00 + 11091.967 0.943750 240558 17.78 + 11165.695 0.950000 242077 20.00 + 11239.423 0.956250 243616 22.86 + 11313.151 0.962500 245370 26.67 + 11403.263 0.968750 246900 32.00 + 11444.223 0.971875 247627 35.56 + 11493.375 0.975000 248378 40.00 + 11509.759 0.978125 249730 45.71 + 11517.951 0.981250 250668 53.33 + 11526.143 0.984375 251637 64.00 + 11526.143 0.985938 251637 71.11 + 11526.143 0.987500 251637 80.00 + 11542.527 0.989062 252040 91.43 + 11558.911 0.990625 252441 106.67 + 11575.295 0.992188 252824 128.00 + 11583.487 0.992969 252994 142.22 + 11599.871 0.993750 253326 160.00 + 11608.063 0.994531 253523 182.86 + 11616.255 0.995313 253676 213.33 + 11624.447 0.996094 253869 256.00 + 11624.447 0.996484 253869 284.44 + 11632.639 0.996875 254066 320.00 + 11632.639 0.997266 254066 365.71 + 11640.831 0.997656 254265 426.67 + 11640.831 0.998047 254265 512.00 + 11649.023 0.998242 254459 568.89 + 11649.023 0.998437 254459 640.00 + 11649.023 0.998633 254459 731.43 + 11649.023 0.998828 254459 853.33 + 11657.215 0.999023 254657 1024.00 + 11657.215 0.999121 254657 1137.78 + 11657.215 0.999219 254657 1280.00 + 11657.215 0.999316 254657 1462.86 + 11657.215 0.999414 254657 1706.67 + 11657.215 0.999512 254657 2048.00 + 11657.215 0.999561 254657 2275.56 + 11657.215 0.999609 254657 2560.00 + 11657.215 0.999658 254657 2925.71 + 11665.407 0.999707 254739 3413.33 + 11665.407 1.000000 254739 inf +#[Mean = 7470.019, StdDeviation = 2382.072] +#[Max = 11657.216, Total count = 254739] +#[Buckets = 27, SubBuckets = 2048] +---------------------------------------------------------- + 385120 requests in 30.00s, 24.61MB read +Requests/sec: 12837.44 +Transfer/sec: 839.95KB + + +-------------------------------------------------------------------------------------------- + +# 1 thread, 1 connection, duration 30 sec, rate 19250 + +./wrk -d 30 -t 1 -c 1 -R 19250 -L -s /home/sbread/Desktop/labs/HLS/2024-highload-dht/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/put.lua http://localhost:8080 +Running 30s test @ http://localhost:8080 + 1 threads and 1 connections + Thread calibration: mean lat.: 1739.191ms, rate sampling interval: 6156ms + Thread Stats Avg Stdev Max +/- Stdev + Latency 6.83s 2.08s 10.17s 53.84% + Req/Sec 12.63k 572.02 13.43k 66.67% + Latency Distribution (HdrHistogram - Recorded Latency) + 50.000% 6.86s + 75.000% 8.90s + 90.000% 9.28s + 99.000% 10.08s + 99.900% 10.17s + 99.990% 10.18s + 99.999% 10.18s +100.000% 10.18s + + Detailed Percentile spectrum: + Value Percentile TotalCount 1/(1-Percentile) + + 3258.367 0.000000 61 1.00 + 3786.751 0.100000 25656 1.11 + 4607.999 0.200000 50443 1.25 + 5472.255 0.300000 76345 1.43 + 5906.431 0.400000 100703 1.67 + 6856.703 0.500000 126769 2.00 + 7233.535 0.550000 138476 2.22 + 7774.207 0.600000 151073 2.50 + 8421.375 0.650000 163657 2.86 + 8847.359 0.700000 177136 3.33 + 8904.703 0.750000 188918 4.00 + 8994.815 0.775000 195082 4.44 + 9035.775 0.800000 201543 5.00 + 9043.967 0.825000 209854 5.71 + 9052.159 0.850000 216419 6.67 + 9109.503 0.875000 220620 8.00 + 9199.615 0.887500 223553 8.89 + 9281.535 0.900000 226598 10.00 + 9461.759 0.912500 229815 11.43 + 9592.831 0.925000 232935 13.33 + 9740.287 0.937500 236006 16.00 + 9789.439 0.943750 237559 17.78 + 9805.823 0.950000 240366 20.00 + 9814.015 0.956250 241751 22.86 + 9822.207 0.962500 243456 26.67 + 9830.399 0.968750 243916 32.00 + 9863.167 0.971875 244773 35.56 + 9895.935 0.975000 245601 40.00 + 9920.511 0.978125 246236 45.71 + 9977.855 0.981250 247097 53.33 + 10027.007 0.984375 247929 64.00 + 10043.391 0.985938 248336 71.11 + 10059.775 0.987500 248747 80.00 + 10076.159 0.989062 249153 91.43 + 10084.351 0.990625 249357 106.67 + 10100.735 0.992188 249773 128.00 + 10108.927 0.992969 249982 142.22 + 10117.119 0.993750 250191 160.00 + 10125.311 0.994531 250397 182.86 + 10133.503 0.995313 250603 213.33 + 10141.695 0.996094 250794 256.00 + 10149.887 0.996484 250998 284.44 + 10149.887 0.996875 250998 320.00 + 10158.079 0.997266 251211 365.71 + 10158.079 0.997656 251211 426.67 + 10166.271 0.998047 251422 512.00 + 10166.271 0.998242 251422 568.89 + 10166.271 0.998437 251422 640.00 + 10166.271 0.998633 251422 731.43 + 10166.271 0.998828 251422 853.33 + 10174.463 0.999023 251631 1024.00 + 10174.463 0.999121 251631 1137.78 + 10174.463 0.999219 251631 1280.00 + 10174.463 0.999316 251631 1462.86 + 10174.463 0.999414 251631 1706.67 + 10174.463 0.999512 251631 2048.00 + 10174.463 0.999561 251631 2275.56 + 10174.463 0.999609 251631 2560.00 + 10174.463 0.999658 251631 2925.71 + 10174.463 0.999707 251631 3413.33 + 10182.655 0.999756 251703 4096.00 + 10182.655 1.000000 251703 inf +#[Mean = 6832.435, StdDeviation = 2082.785] +#[Max = 10174.464, Total count = 251703] +#[Buckets = 27, SubBuckets = 2048] +---------------------------------------------------------- + 381577 requests in 30.00s, 24.38MB read +Requests/sec: 12719.26 +Transfer/sec: 832.22KB + +-------------------------------------------------------------------------------------------- + +# 1 thread, 1 connection, duration 30 sec, rate 18500 + +./wrk -d 30 -t 1 -c 1 -R 18500 -L -s /home/sbread/Desktop/labs/HLS/2024-highload-dht/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/put.lua http://localhost:8080 +Running 30s test @ http://localhost:8080 + 1 threads and 1 connections + Thread calibration: mean lat.: 967.138ms, rate sampling interval: 2824ms + Thread Stats Avg Stdev Max +/- Stdev + Latency 4.05s 1.60s 7.22s 52.96% + Req/Sec 13.47k 1.76k 15.56k 57.14% + Latency Distribution (HdrHistogram - Recorded Latency) + 50.000% 4.40s + 75.000% 5.31s + 90.000% 6.33s + 99.000% 7.13s + 99.900% 7.22s + 99.990% 7.23s + 99.999% 7.23s +100.000% 7.23s + + Detailed Percentile spectrum: + Value Percentile TotalCount 1/(1-Percentile) + + 1752.063 0.000000 196 1.00 + 1980.415 0.100000 26925 1.11 + 2197.503 0.200000 53754 1.25 + 2496.511 0.300000 80607 1.43 + 3579.903 0.400000 107472 1.67 + 4399.103 0.500000 134505 2.00 + 4419.583 0.550000 149559 2.22 + 4452.351 0.600000 162083 2.50 + 4669.439 0.650000 174639 2.86 + 5013.503 0.700000 188247 3.33 + 5308.415 0.750000 201650 4.00 + 5419.007 0.775000 208273 4.44 + 5574.655 0.800000 214956 5.00 + 5693.439 0.825000 221664 5.71 + 5832.703 0.850000 228454 6.67 + 6078.463 0.875000 235091 8.00 + 6205.439 0.887500 238534 8.89 + 6332.415 0.900000 241860 10.00 + 6463.487 0.912500 245175 11.43 + 6586.367 0.925000 248539 13.33 + 6676.479 0.937500 251926 16.00 + 6721.535 0.943750 253619 17.78 + 6754.303 0.950000 255331 20.00 + 6795.263 0.956250 256958 22.86 + 6856.703 0.962500 258633 26.67 + 6918.143 0.968750 260317 32.00 + 6950.911 0.971875 261219 35.56 + 6979.583 0.975000 262015 40.00 + 7008.255 0.978125 262800 45.71 + 7041.023 0.981250 263682 53.33 + 7069.695 0.984375 264485 64.00 + 7086.079 0.985938 264937 71.11 + 7102.463 0.987500 265384 80.00 + 7118.847 0.989062 265812 91.43 + 7135.231 0.990625 266260 106.67 + 7147.519 0.992188 266605 128.00 + 7155.711 0.992969 266824 142.22 + 7163.903 0.993750 267052 160.00 + 7172.095 0.994531 267278 182.86 + 7180.287 0.995313 267494 213.33 + 7188.479 0.996094 267715 256.00 + 7192.575 0.996484 267829 284.44 + 7196.671 0.996875 267942 320.00 + 7196.671 0.997266 267942 365.71 + 7200.767 0.997656 268057 426.67 + 7204.863 0.998047 268170 512.00 + 7208.959 0.998242 268282 568.89 + 7208.959 0.998437 268282 640.00 + 7213.055 0.998633 268396 731.43 + 7213.055 0.998828 268396 853.33 + 7217.151 0.999023 268510 1024.00 + 7217.151 0.999121 268510 1137.78 + 7217.151 0.999219 268510 1280.00 + 7217.151 0.999316 268510 1462.86 + 7221.247 0.999414 268623 1706.67 + 7221.247 0.999512 268623 2048.00 + 7221.247 0.999561 268623 2275.56 + 7221.247 0.999609 268623 2560.00 + 7221.247 0.999658 268623 2925.71 + 7221.247 0.999707 268623 3413.33 + 7221.247 0.999756 268623 4096.00 + 7221.247 0.999780 268623 4551.11 + 7221.247 0.999805 268623 5120.00 + 7225.343 0.999829 268671 5851.43 + 7225.343 1.000000 268671 inf +#[Mean = 4051.823, StdDeviation = 1602.790] +#[Max = 7221.248, Total count = 268671] +#[Buckets = 27, SubBuckets = 2048] +---------------------------------------------------------- + 421361 requests in 30.00s, 26.92MB read +Requests/sec: 14045.50 +Transfer/sec: 0.90MB + +--------------------------------------------------------------------------------- + +# seq put. first + +# 1 thread, 1 connection, duration 30 sec, rate 18500 + +./wrk -d 30 -t 1 -c 1 -R 18500 -L -s /home/sbread/Desktop/labs/HLS/2024-highload-dht/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/put.lua http://localhost:8080 +Running 30s test @ http://localhost:8080 + 1 threads and 1 connections + Thread calibration: mean lat.: 8.537ms, rate sampling interval: 71ms + Thread Stats Avg Stdev Max +/- Stdev + Latency 2.19ms 4.96ms 47.10ms 94.54% + Req/Sec 18.65k 824.21 21.93k 86.12% + Latency Distribution (HdrHistogram - Recorded Latency) + 50.000% 0.93ms + 75.000% 1.58ms + 90.000% 4.34ms + 99.000% 31.68ms + 99.900% 46.56ms + 99.990% 47.10ms + 99.999% 47.13ms +100.000% 47.13ms + + Detailed Percentile spectrum: + Value Percentile TotalCount 1/(1-Percentile) + + 0.033 0.000000 1 1.00 + 0.251 0.100000 37011 1.11 + 0.436 0.200000 74198 1.25 + 0.609 0.300000 111129 1.43 + 0.782 0.400000 148071 1.67 + 0.930 0.500000 184980 2.00 + 1.003 0.550000 203669 2.22 + 1.074 0.600000 222006 2.50 + 1.155 0.650000 240528 2.86 + 1.318 0.700000 258960 3.33 + 1.575 0.750000 277480 4.00 + 1.738 0.775000 286674 4.44 + 1.956 0.800000 295927 5.00 + 2.253 0.825000 305185 5.71 + 2.705 0.850000 314419 6.67 + 3.301 0.875000 323668 8.00 + 3.701 0.887500 328293 8.89 + 4.343 0.900000 332914 10.00 + 4.951 0.912500 337536 11.43 + 5.527 0.925000 342173 13.33 + 6.419 0.937500 346788 16.00 + 6.987 0.943750 349114 17.78 + 7.715 0.950000 351418 20.00 + 8.951 0.956250 353719 22.86 + 10.511 0.962500 356032 26.67 + 12.407 0.968750 358364 32.00 + 12.887 0.971875 359505 35.56 + 14.663 0.975000 360662 40.00 + 16.543 0.978125 361813 45.71 + 17.855 0.981250 362978 53.33 + 22.527 0.984375 364123 64.00 + 26.607 0.985938 364705 71.11 + 28.623 0.987500 365278 80.00 + 29.487 0.989062 365863 91.43 + 33.599 0.990625 366434 106.67 + 35.551 0.992188 367015 128.00 + 36.351 0.992969 367304 142.22 + 37.023 0.993750 367598 160.00 + 37.727 0.994531 367926 182.86 + 38.943 0.995313 368175 213.33 + 40.831 0.996094 368459 256.00 + 41.695 0.996484 368625 284.44 + 42.495 0.996875 368749 320.00 + 43.295 0.997266 368890 365.71 + 44.511 0.997656 369040 426.67 + 45.631 0.998047 369180 512.00 + 46.015 0.998242 369274 568.89 + 46.079 0.998437 369347 640.00 + 46.175 0.998633 369417 731.43 + 46.271 0.998828 369468 853.33 + 46.559 0.999023 369565 1024.00 + 46.591 0.999121 369592 1137.78 + 46.655 0.999219 369618 1280.00 + 46.911 0.999316 369650 1462.86 + 47.039 0.999414 369771 1706.67 + 47.039 0.999512 369771 2048.00 + 47.039 0.999561 369771 2275.56 + 47.039 0.999609 369771 2560.00 + 47.071 0.999658 369854 2925.71 + 47.071 0.999707 369854 3413.33 + 47.071 0.999756 369854 4096.00 + 47.071 0.999780 369854 4551.11 + 47.071 0.999805 369854 5120.00 + 47.071 0.999829 369854 5851.43 + 47.071 0.999854 369854 6826.67 + 47.103 0.999878 369892 8192.00 + 47.103 0.999890 369892 9102.22 + 47.103 0.999902 369892 10240.00 + 47.103 0.999915 369892 11702.86 + 47.103 0.999927 369892 13653.33 + 47.103 0.999939 369892 16384.00 + 47.103 0.999945 369892 18204.44 + 47.103 0.999951 369892 20480.00 + 47.103 0.999957 369892 23405.71 + 47.103 0.999963 369892 27306.67 + 47.103 0.999969 369892 32768.00 + 47.103 0.999973 369892 36408.89 + 47.103 0.999976 369892 40960.00 + 47.135 0.999979 369901 46811.43 + 47.135 1.000000 369901 inf +#[Mean = 2.186, StdDeviation = 4.956] +#[Max = 47.104, Total count = 369901] +#[Buckets = 27, SubBuckets = 2048] +---------------------------------------------------------- + 554975 requests in 30.00s, 35.46MB read +Requests/sec: 18499.22 +Transfer/sec: 1.18MB + +--------------------------------------------------------------------------------- + +# seq put. second + +# 1 thread, 1 connection, duration 30 sec, rate 18500 + +./wrk -d 30 -t 1 -c 1 -R 18500 -L -s /home/sbread/Desktop/labs/HLS/2024-highload-dht/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/put.lua http://localhost:8080 +Running 30s test @ http://localhost:8080 + 1 threads and 1 connections + Thread calibration: mean lat.: 2.082ms, rate sampling interval: 11ms + Thread Stats Avg Stdev Max +/- Stdev + Latency 16.91ms 38.56ms 178.94ms 89.21% + Req/Sec 19.51k 2.43k 25.10k 74.79% + Latency Distribution (HdrHistogram - Recorded Latency) + 50.000% 1.18ms + 75.000% 8.66ms + 90.000% 69.44ms + 99.000% 162.69ms + 99.900% 178.56ms + 99.990% 179.07ms + 99.999% 179.07ms +100.000% 179.07ms + + Detailed Percentile spectrum: + Value Percentile TotalCount 1/(1-Percentile) + + 0.033 0.000000 1 1.00 + 0.316 0.100000 37092 1.11 + 0.564 0.200000 74013 1.25 + 0.792 0.300000 110874 1.43 + 0.977 0.400000 147907 1.67 + 1.184 0.500000 184845 2.00 + 1.462 0.550000 203285 2.22 + 2.139 0.600000 221751 2.50 + 3.505 0.650000 240236 2.86 + 5.775 0.700000 258715 3.33 + 8.663 0.750000 277249 4.00 + 10.535 0.775000 286417 4.44 + 13.303 0.800000 295658 5.00 + 16.719 0.825000 304895 5.71 + 21.327 0.850000 314160 6.67 + 31.855 0.875000 323378 8.00 + 47.231 0.887500 328002 8.89 + 69.503 0.900000 332620 10.00 + 83.071 0.912500 337316 11.43 + 87.423 0.925000 341901 13.33 + 107.391 0.937500 346474 16.00 + 119.551 0.943750 348782 17.78 + 131.071 0.950000 351092 20.00 + 144.895 0.956250 353424 22.86 + 150.783 0.962500 355768 26.67 + 152.575 0.968750 358191 32.00 + 153.087 0.971875 359189 35.56 + 153.727 0.975000 360425 40.00 + 154.879 0.978125 361538 45.71 + 156.415 0.981250 362685 53.33 + 157.823 0.984375 363818 64.00 + 158.847 0.985938 364385 71.11 + 159.999 0.987500 365016 80.00 + 161.663 0.989062 365547 91.43 + 162.943 0.990625 366116 106.67 + 164.223 0.992188 366760 128.00 + 164.991 0.992969 366985 142.22 + 166.783 0.993750 367266 160.00 + 168.959 0.994531 367549 182.86 + 171.135 0.995313 367869 213.33 + 173.183 0.996094 368136 256.00 + 173.823 0.996484 368275 284.44 + 174.335 0.996875 368439 320.00 + 175.103 0.997266 368568 365.71 + 176.255 0.997656 368749 426.67 + 176.895 0.998047 368853 512.00 + 177.535 0.998242 368927 568.89 + 178.175 0.998437 369005 640.00 + 178.303 0.998633 369081 731.43 + 178.431 0.998828 369197 853.33 + 178.559 0.999023 369281 1024.00 + 178.559 0.999121 369281 1137.78 + 178.559 0.999219 369281 1280.00 + 178.687 0.999316 369363 1462.86 + 178.687 0.999414 369363 1706.67 + 178.815 0.999512 369476 2048.00 + 178.815 0.999561 369476 2275.56 + 178.815 0.999609 369476 2560.00 + 178.815 0.999658 369476 2925.71 + 178.815 0.999707 369476 3413.33 + 178.943 0.999756 369518 4096.00 + 178.943 0.999780 369518 4551.11 + 178.943 0.999805 369518 5120.00 + 178.943 0.999829 369518 5851.43 + 178.943 0.999854 369518 6826.67 + 179.071 0.999878 369569 8192.00 + 179.071 1.000000 369569 inf +#[Mean = 16.907, StdDeviation = 38.560] +#[Max = 178.944, Total count = 369569] +#[Buckets = 27, SubBuckets = 2048] +---------------------------------------------------------- + 554632 requests in 30.00s, 35.44MB read +Requests/sec: 18487.77 +Transfer/sec: 1.18MB + + +--------------------------------------------------------------------------------- + +# seq put. third + +# 1 thread, 1 connection, duration 30 sec, rate 18500 + +./wrk -d 30 -t 1 -c 1 -R 18500 -L -s /home/sbread/Desktop/labs/HLS/2024-highload-dht/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/put.lua http://localhost:8080 +Running 30s test @ http://localhost:8080 + 1 threads and 1 connections + Thread calibration: mean lat.: 28.364ms, rate sampling interval: 210ms + Thread Stats Avg Stdev Max +/- Stdev + Latency 2.34ms 4.27ms 29.54ms 91.09% + Req/Sec 18.57k 475.96 20.17k 83.16% + Latency Distribution (HdrHistogram - Recorded Latency) + 50.000% 0.93ms + 75.000% 1.63ms + 90.000% 5.84ms + 99.000% 24.74ms + 99.900% 28.61ms + 99.990% 29.49ms + 99.999% 29.55ms +100.000% 29.55ms + + Detailed Percentile spectrum: + Value Percentile TotalCount 1/(1-Percentile) + + 0.033 0.000000 1 1.00 + 0.247 0.100000 37189 1.11 + 0.427 0.200000 74249 1.25 + 0.606 0.300000 111270 1.43 + 0.779 0.400000 148172 1.67 + 0.930 0.500000 185184 2.00 + 1.000 0.550000 203767 2.22 + 1.070 0.600000 222322 2.50 + 1.141 0.650000 240806 2.86 + 1.315 0.700000 259200 3.33 + 1.632 0.750000 277722 4.00 + 1.923 0.775000 286954 4.44 + 2.353 0.800000 296204 5.00 + 2.927 0.825000 305473 5.71 + 3.635 0.850000 314721 6.67 + 4.575 0.875000 323985 8.00 + 5.199 0.887500 328609 8.89 + 5.839 0.900000 333221 10.00 + 6.739 0.912500 337854 11.43 + 7.819 0.925000 342488 13.33 + 8.583 0.937500 347111 16.00 + 9.927 0.943750 349419 17.78 + 11.391 0.950000 351734 20.00 + 12.743 0.956250 354043 22.86 + 14.383 0.962500 356359 26.67 + 15.423 0.968750 358677 32.00 + 16.559 0.971875 359834 35.56 + 17.327 0.975000 361002 40.00 + 18.207 0.978125 362148 45.71 + 19.567 0.981250 363300 53.33 + 20.607 0.984375 364462 64.00 + 21.183 0.985938 365035 71.11 + 21.935 0.987500 365621 80.00 + 23.567 0.989062 366194 91.43 + 24.863 0.990625 366777 106.67 + 25.215 0.992188 367371 128.00 + 25.471 0.992969 367639 142.22 + 26.063 0.993750 367940 160.00 + 26.239 0.994531 368261 182.86 + 26.319 0.995313 368530 213.33 + 26.447 0.996094 368824 256.00 + 26.495 0.996484 368943 284.44 + 26.559 0.996875 369085 320.00 + 26.671 0.997266 369241 365.71 + 27.023 0.997656 369379 426.67 + 28.031 0.998047 369519 512.00 + 28.159 0.998242 369596 568.89 + 28.271 0.998437 369669 640.00 + 28.383 0.998633 369742 731.43 + 28.543 0.998828 369816 853.33 + 28.623 0.999023 369885 1024.00 + 28.687 0.999121 369919 1137.78 + 28.719 0.999219 369952 1280.00 + 28.767 0.999316 369990 1462.86 + 28.815 0.999414 370035 1706.67 + 28.863 0.999512 370080 2048.00 + 28.863 0.999561 370080 2275.56 + 28.895 0.999609 370097 2560.00 + 28.975 0.999658 370118 2925.71 + 29.103 0.999707 370134 3413.33 + 29.263 0.999756 370152 4096.00 + 29.327 0.999780 370160 4551.11 + 29.407 0.999805 370170 5120.00 + 29.423 0.999829 370180 5851.43 + 29.439 0.999854 370195 6826.67 + 29.455 0.999878 370197 8192.00 + 29.471 0.999890 370203 9102.22 + 29.487 0.999902 370205 10240.00 + 29.503 0.999915 370213 11702.86 + 29.519 0.999927 370222 13653.33 + 29.519 0.999939 370222 16384.00 + 29.519 0.999945 370222 18204.44 + 29.535 0.999951 370230 20480.00 + 29.535 0.999957 370230 23405.71 + 29.535 0.999963 370230 27306.67 + 29.535 0.999969 370230 32768.00 + 29.551 0.999973 370241 36408.89 + 29.551 1.000000 370241 inf +#[Mean = 2.337, StdDeviation = 4.271] +#[Max = 29.536, Total count = 370241] +#[Buckets = 27, SubBuckets = 2048] +---------------------------------------------------------- + 554982 requests in 30.00s, 35.46MB read +Requests/sec: 18499.44 +Transfer/sec: 1.18MB + + From 003154250e20d21def91e84f5e25e1b42e13fd81 Mon Sep 17 00:00:00 2001 From: sbread Date: Wed, 6 Mar 2024 19:54:18 +0300 Subject: [PATCH 08/23] hw2 code --- build.gradle | 6 -- .../vk/itmo/test/osipovdaniil/ServerImpl.java | 85 +++++++++++++------ .../test/osipovdaniil/ServiceFactoryImpl.java | 2 +- .../{ => report1}/asyncprof/delete alloc.html | 0 .../{ => report1}/asyncprof/delete cpu.html | 0 .../{ => report1}/asyncprof/get alloc.html | 0 .../{ => report1}/asyncprof/get cpu.html | 0 .../{ => report1}/asyncprof/put alloc.html | 0 .../{ => report1}/asyncprof/put cpu.html | 0 .../test/osipovdaniil/{ => report1}/report.md | 0 .../osipovdaniil/{ => report1}/wrk/delete | 0 .../test/osipovdaniil/{ => report1}/wrk/get | 0 .../test/osipovdaniil/{ => report1}/wrk/put | 0 13 files changed, 62 insertions(+), 31 deletions(-) rename src/main/java/ru/vk/itmo/test/osipovdaniil/{ => report1}/asyncprof/delete alloc.html (100%) rename src/main/java/ru/vk/itmo/test/osipovdaniil/{ => report1}/asyncprof/delete cpu.html (100%) rename src/main/java/ru/vk/itmo/test/osipovdaniil/{ => report1}/asyncprof/get alloc.html (100%) rename src/main/java/ru/vk/itmo/test/osipovdaniil/{ => report1}/asyncprof/get cpu.html (100%) rename src/main/java/ru/vk/itmo/test/osipovdaniil/{ => report1}/asyncprof/put alloc.html (100%) rename src/main/java/ru/vk/itmo/test/osipovdaniil/{ => report1}/asyncprof/put cpu.html (100%) rename src/main/java/ru/vk/itmo/test/osipovdaniil/{ => report1}/report.md (100%) rename src/main/java/ru/vk/itmo/test/osipovdaniil/{ => report1}/wrk/delete (100%) rename src/main/java/ru/vk/itmo/test/osipovdaniil/{ => report1}/wrk/get (100%) rename src/main/java/ru/vk/itmo/test/osipovdaniil/{ => report1}/wrk/put (100%) diff --git a/build.gradle b/build.gradle index 12b79b092..72bdaa903 100644 --- a/build.gradle +++ b/build.gradle @@ -67,9 +67,3 @@ compileJava { compileTestJava { options.compilerArgs += ["--enable-preview"] } - -run { - maxHeapSize = "128m" - jvmArgs += ["--enable-preview"] - mainClassName = 'ru.vk.itmo.test.osipovdaniil.Server' -} diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java index 5f0ec636d..48c1928d9 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java @@ -1,13 +1,6 @@ package ru.vk.itmo.test.osipovdaniil; -import one.nio.http.HttpServer; -import one.nio.http.HttpServerConfig; -import one.nio.http.HttpSession; -import one.nio.http.Param; -import one.nio.http.Path; -import one.nio.http.Request; -import one.nio.http.RequestMethod; -import one.nio.http.Response; +import one.nio.http.*; import one.nio.server.AcceptorConfig; import ru.vk.itmo.ServiceConfig; import ru.vk.itmo.dao.BaseEntry; @@ -18,17 +11,28 @@ import java.lang.foreign.MemorySegment; import java.lang.foreign.ValueLayout; import java.nio.charset.StandardCharsets; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.TimeUnit; import java.util.function.Function; +import java.util.logging.Logger; public class ServerImpl extends HttpServer { private static final String ENTITY_PATH = "/v0/entity"; + private static final String ID = "id="; + private final ExecutorService requestExecutor; + private final Logger logger; + private static final Integer maxThreads = 64; private final ReferenceDao dao; public ServerImpl(final ServiceConfig serviceConfig, ReferenceDao dao) throws IOException { super(createHttpServerConfig(serviceConfig)); this.dao = dao; + this.requestExecutor = Executors.newFixedThreadPool(maxThreads); + this.logger = Logger.getLogger(ServerImpl.class.getName()); } private static HttpServerConfig createHttpServerConfig(final ServiceConfig serviceConfig) { @@ -36,7 +40,7 @@ private static HttpServerConfig createHttpServerConfig(final ServiceConfig servi final AcceptorConfig acceptorConfig = new AcceptorConfig(); acceptorConfig.port = serviceConfig.selfPort(); acceptorConfig.reusePort = true; - httpServerConfig.acceptors = new AcceptorConfig[] { acceptorConfig }; + httpServerConfig.acceptors = new AcceptorConfig[]{acceptorConfig}; httpServerConfig.closeSessions = true; return httpServerConfig; } @@ -85,24 +89,57 @@ public Response put(@Param("id") final String id, final Request value) { }); } + private void handleRequestTask(final Request request, final HttpSession session) { + try { + Response response; + if (!request.getPath().startsWith(ENTITY_PATH)) { + response = new Response(Response.BAD_REQUEST, Response.EMPTY); + session.sendResponse(response); + return; + } + final int method = request.getMethod(); + if (method == Request.METHOD_GET) { + response = get(request.getParameter(ID)); + } else if (method == Request.METHOD_DELETE) { + response = delete(request.getParameter(ID)); + } else if (method == Request.METHOD_PUT) { + response = put(request.getParameter(ID), request); + } else { + response = new Response(Response.METHOD_NOT_ALLOWED, Response.EMPTY); + } + session.sendResponse(response); + } catch (IOException e) { + logger.info("IO exception in execution request: " + request + "\n" + e); + throw new RuntimeException(e); + } + } + @Override public void handleRequest(final Request request, final HttpSession session) throws IOException { - Response response; - if (!request.getPath().startsWith(ENTITY_PATH)) { - response = new Response(Response.BAD_REQUEST, Response.EMPTY); - session.sendResponse(response); - return; + try { + requestExecutor.execute(() -> handleRequestTask(request, session)); + } catch (RejectedExecutionException e) { + logger.info("Execution has been rejected in request: " + request + "\n" + e); + session.sendError(Response.SERVICE_UNAVAILABLE, ""); } - final int method = request.getMethod(); - if (method == Request.METHOD_GET) { - response = get(request.getParameter("id=")); - } else if (method == Request.METHOD_DELETE) { - response = delete(request.getParameter("id=")); - } else if (method == Request.METHOD_PUT) { - response = put(request.getParameter("id="), request); - } else { - response = new Response(Response.METHOD_NOT_ALLOWED, Response.EMPTY); + } + + void shutdownAndAwaitTermination(ExecutorService pool) { + try { + if (!pool.awaitTermination(60, TimeUnit.MILLISECONDS)) { + pool.shutdownNow(); + if (!pool.awaitTermination(60, TimeUnit.MILLISECONDS)) + logger.info("Pool did not terminate"); + } + } catch (InterruptedException ie) { + pool.shutdownNow(); + Thread.currentThread().interrupt(); } - session.sendResponse(response); + } + + @Override + public synchronized void stop() { + shutdownAndAwaitTermination(requestExecutor); + super.stop(); } } diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/ServiceFactoryImpl.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/ServiceFactoryImpl.java index dd9363932..2eed10d26 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/ServiceFactoryImpl.java +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/ServiceFactoryImpl.java @@ -4,7 +4,7 @@ import ru.vk.itmo.ServiceConfig; import ru.vk.itmo.test.ServiceFactory; -@ServiceFactory(stage = 1) +@ServiceFactory(stage = 2) public class ServiceFactoryImpl implements ServiceFactory.Factory { @Override diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/asyncprof/delete alloc.html b/src/main/java/ru/vk/itmo/test/osipovdaniil/report1/asyncprof/delete alloc.html similarity index 100% rename from src/main/java/ru/vk/itmo/test/osipovdaniil/asyncprof/delete alloc.html rename to src/main/java/ru/vk/itmo/test/osipovdaniil/report1/asyncprof/delete alloc.html diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/asyncprof/delete cpu.html b/src/main/java/ru/vk/itmo/test/osipovdaniil/report1/asyncprof/delete cpu.html similarity index 100% rename from src/main/java/ru/vk/itmo/test/osipovdaniil/asyncprof/delete cpu.html rename to src/main/java/ru/vk/itmo/test/osipovdaniil/report1/asyncprof/delete cpu.html diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/asyncprof/get alloc.html b/src/main/java/ru/vk/itmo/test/osipovdaniil/report1/asyncprof/get alloc.html similarity index 100% rename from src/main/java/ru/vk/itmo/test/osipovdaniil/asyncprof/get alloc.html rename to src/main/java/ru/vk/itmo/test/osipovdaniil/report1/asyncprof/get alloc.html diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/asyncprof/get cpu.html b/src/main/java/ru/vk/itmo/test/osipovdaniil/report1/asyncprof/get cpu.html similarity index 100% rename from src/main/java/ru/vk/itmo/test/osipovdaniil/asyncprof/get cpu.html rename to src/main/java/ru/vk/itmo/test/osipovdaniil/report1/asyncprof/get cpu.html diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/asyncprof/put alloc.html b/src/main/java/ru/vk/itmo/test/osipovdaniil/report1/asyncprof/put alloc.html similarity index 100% rename from src/main/java/ru/vk/itmo/test/osipovdaniil/asyncprof/put alloc.html rename to src/main/java/ru/vk/itmo/test/osipovdaniil/report1/asyncprof/put alloc.html diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/asyncprof/put cpu.html b/src/main/java/ru/vk/itmo/test/osipovdaniil/report1/asyncprof/put cpu.html similarity index 100% rename from src/main/java/ru/vk/itmo/test/osipovdaniil/asyncprof/put cpu.html rename to src/main/java/ru/vk/itmo/test/osipovdaniil/report1/asyncprof/put cpu.html diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/report.md b/src/main/java/ru/vk/itmo/test/osipovdaniil/report1/report.md similarity index 100% rename from src/main/java/ru/vk/itmo/test/osipovdaniil/report.md rename to src/main/java/ru/vk/itmo/test/osipovdaniil/report1/report.md diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/wrk/delete b/src/main/java/ru/vk/itmo/test/osipovdaniil/report1/wrk/delete similarity index 100% rename from src/main/java/ru/vk/itmo/test/osipovdaniil/wrk/delete rename to src/main/java/ru/vk/itmo/test/osipovdaniil/report1/wrk/delete diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/wrk/get b/src/main/java/ru/vk/itmo/test/osipovdaniil/report1/wrk/get similarity index 100% rename from src/main/java/ru/vk/itmo/test/osipovdaniil/wrk/get rename to src/main/java/ru/vk/itmo/test/osipovdaniil/report1/wrk/get diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/wrk/put b/src/main/java/ru/vk/itmo/test/osipovdaniil/report1/wrk/put similarity index 100% rename from src/main/java/ru/vk/itmo/test/osipovdaniil/wrk/put rename to src/main/java/ru/vk/itmo/test/osipovdaniil/report1/wrk/put From 15fc311899ba6c77025edea55df1ee7b81141773 Mon Sep 17 00:00:00 2001 From: sbread Date: Wed, 6 Mar 2024 20:03:53 +0300 Subject: [PATCH 09/23] codeclimate --- .../ru/vk/itmo/test/osipovdaniil/ServerImpl.java | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java index 48c1928d9..f6ac4eb1c 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java @@ -1,6 +1,13 @@ package ru.vk.itmo.test.osipovdaniil; -import one.nio.http.*; +import one.nio.http.HttpServer; +import one.nio.http.HttpServerConfig; +import one.nio.http.HttpSession; +import one.nio.http.Param; +import one.nio.http.Path; +import one.nio.http.Request; +import one.nio.http.RequestMethod; +import one.nio.http.Response; import one.nio.server.AcceptorConfig; import ru.vk.itmo.ServiceConfig; import ru.vk.itmo.dao.BaseEntry; @@ -8,6 +15,7 @@ import ru.vk.itmo.test.osipovdaniil.dao.ReferenceDao; import java.io.IOException; +import java.io.UncheckedIOException; import java.lang.foreign.MemorySegment; import java.lang.foreign.ValueLayout; import java.nio.charset.StandardCharsets; @@ -110,7 +118,7 @@ private void handleRequestTask(final Request request, final HttpSession session) session.sendResponse(response); } catch (IOException e) { logger.info("IO exception in execution request: " + request + "\n" + e); - throw new RuntimeException(e); + throw new UncheckedIOException(e); } } @@ -128,8 +136,9 @@ void shutdownAndAwaitTermination(ExecutorService pool) { try { if (!pool.awaitTermination(60, TimeUnit.MILLISECONDS)) { pool.shutdownNow(); - if (!pool.awaitTermination(60, TimeUnit.MILLISECONDS)) + if (!pool.awaitTermination(60, TimeUnit.MILLISECONDS)) { logger.info("Pool did not terminate"); + } } } catch (InterruptedException ie) { pool.shutdownNow(); From 1ee4dd7a87e025452a2915d5add4a87a55f8f516 Mon Sep 17 00:00:00 2001 From: sbread Date: Wed, 6 Mar 2024 20:06:54 +0300 Subject: [PATCH 10/23] codeclimate 2 --- .../java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java index f6ac4eb1c..a0e132dfb 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java @@ -29,17 +29,17 @@ public class ServerImpl extends HttpServer { private static final String ENTITY_PATH = "/v0/entity"; + private static final Integer MAX_THREADS = 64; private static final String ID = "id="; private final ExecutorService requestExecutor; private final Logger logger; - private static final Integer maxThreads = 64; private final ReferenceDao dao; public ServerImpl(final ServiceConfig serviceConfig, ReferenceDao dao) throws IOException { super(createHttpServerConfig(serviceConfig)); this.dao = dao; - this.requestExecutor = Executors.newFixedThreadPool(maxThreads); + this.requestExecutor = Executors.newFixedThreadPool(MAX_THREADS); this.logger = Logger.getLogger(ServerImpl.class.getName()); } @@ -117,7 +117,7 @@ private void handleRequestTask(final Request request, final HttpSession session) } session.sendResponse(response); } catch (IOException e) { - logger.info("IO exception in execution request: " + request + "\n" + e); + logger.info("IO exception in execution request: " + request + "\n"); throw new UncheckedIOException(e); } } @@ -127,7 +127,7 @@ public void handleRequest(final Request request, final HttpSession session) thro try { requestExecutor.execute(() -> handleRequestTask(request, session)); } catch (RejectedExecutionException e) { - logger.info("Execution has been rejected in request: " + request + "\n" + e); + logger.info("Execution has been rejected in request: " + request + "\n"); session.sendError(Response.SERVICE_UNAVAILABLE, ""); } } From 7f8e7f817840f95b6ac621602d5876c7044b2070 Mon Sep 17 00:00:00 2001 From: sbread Date: Wed, 6 Mar 2024 22:08:19 +0300 Subject: [PATCH 11/23] report2 --- .../report2/asyncprof/prof_128_alloc_get.html | 450 +++ .../report2/asyncprof/prof_128_alloc_put.html | 513 +++ .../report2/asyncprof/prof_128_cpu_get.html | 3057 +++++++++++++++ .../report2/asyncprof/prof_128_cpu_put.html | 3459 +++++++++++++++++ .../report2/asyncprof/prof_128_lock_get.html | 336 ++ .../report2/asyncprof/prof_128_lock_put.html | 385 ++ .../report2/asyncprof/prof_64_alloc_get.html | 450 +++ .../report2/asyncprof/prof_64_alloc_put.html | 506 +++ .../report2/asyncprof/prof_64_cpu_get.html | 1838 +++++++++ .../report2/asyncprof/prof_64_cpu_put.html | 2284 +++++++++++ .../report2/asyncprof/prof_64_lock_get.html | 336 ++ .../report2/asyncprof/prof_64_lock_put.html | 356 ++ .../report2/graphics/percentiles.png | Bin 0 -> 152055 bytes .../itmo/test/osipovdaniil/report2/report2.md | 28 + .../vk/itmo/test/osipovdaniil/report2/wrk/wrk | 724 ++++ 15 files changed, 14722 insertions(+) create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/report2/asyncprof/prof_128_alloc_get.html create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/report2/asyncprof/prof_128_alloc_put.html create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/report2/asyncprof/prof_128_cpu_get.html create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/report2/asyncprof/prof_128_cpu_put.html create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/report2/asyncprof/prof_128_lock_get.html create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/report2/asyncprof/prof_128_lock_put.html create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/report2/asyncprof/prof_64_alloc_get.html create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/report2/asyncprof/prof_64_alloc_put.html create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/report2/asyncprof/prof_64_cpu_get.html create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/report2/asyncprof/prof_64_cpu_put.html create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/report2/asyncprof/prof_64_lock_get.html create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/report2/asyncprof/prof_64_lock_put.html create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/report2/graphics/percentiles.png create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/report2/report2.md create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/report2/wrk/wrk diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/report2/asyncprof/prof_128_alloc_get.html b/src/main/java/ru/vk/itmo/test/osipovdaniil/report2/asyncprof/prof_128_alloc_get.html new file mode 100644 index 000000000..0b84466be --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/report2/asyncprof/prof_128_alloc_get.html @@ -0,0 +1,450 @@ + + + + + + + +

Allocation profile

+
  
+
Produced by async-profiler
+ +
+

+

Matched:

+ diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/report2/asyncprof/prof_128_alloc_put.html b/src/main/java/ru/vk/itmo/test/osipovdaniil/report2/asyncprof/prof_128_alloc_put.html new file mode 100644 index 000000000..d6ec65935 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/report2/asyncprof/prof_128_alloc_put.html @@ -0,0 +1,513 @@ + + + + + + + +

Allocation profile

+
  
+
Produced by async-profiler
+ +
+

+

Matched:

+ diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/report2/asyncprof/prof_128_cpu_get.html b/src/main/java/ru/vk/itmo/test/osipovdaniil/report2/asyncprof/prof_128_cpu_get.html new file mode 100644 index 000000000..d40978e08 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/report2/asyncprof/prof_128_cpu_get.html @@ -0,0 +1,3057 @@ + + + + + + + +

CPU profile

+
  
+
Produced by async-profiler
+ +
+

+

Matched:

+ diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/report2/asyncprof/prof_128_cpu_put.html b/src/main/java/ru/vk/itmo/test/osipovdaniil/report2/asyncprof/prof_128_cpu_put.html new file mode 100644 index 000000000..125d29c51 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/report2/asyncprof/prof_128_cpu_put.html @@ -0,0 +1,3459 @@ + + + + + + + +

CPU profile

+
  
+
Produced by async-profiler
+ +
+

+

Matched:

+ diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/report2/asyncprof/prof_128_lock_get.html b/src/main/java/ru/vk/itmo/test/osipovdaniil/report2/asyncprof/prof_128_lock_get.html new file mode 100644 index 000000000..21cb3df56 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/report2/asyncprof/prof_128_lock_get.html @@ -0,0 +1,336 @@ + + + + + + + +

Lock profile

+
  
+
Produced by async-profiler
+ +
+

+

Matched:

+ diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/report2/asyncprof/prof_128_lock_put.html b/src/main/java/ru/vk/itmo/test/osipovdaniil/report2/asyncprof/prof_128_lock_put.html new file mode 100644 index 000000000..457857562 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/report2/asyncprof/prof_128_lock_put.html @@ -0,0 +1,385 @@ + + + + + + + +

Lock profile

+
  
+
Produced by async-profiler
+ +
+

+

Matched:

+ diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/report2/asyncprof/prof_64_alloc_get.html b/src/main/java/ru/vk/itmo/test/osipovdaniil/report2/asyncprof/prof_64_alloc_get.html new file mode 100644 index 000000000..faa15901a --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/report2/asyncprof/prof_64_alloc_get.html @@ -0,0 +1,450 @@ + + + + + + + +

Allocation profile

+
  
+
Produced by async-profiler
+ +
+

+

Matched:

+ diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/report2/asyncprof/prof_64_alloc_put.html b/src/main/java/ru/vk/itmo/test/osipovdaniil/report2/asyncprof/prof_64_alloc_put.html new file mode 100644 index 000000000..5408c1122 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/report2/asyncprof/prof_64_alloc_put.html @@ -0,0 +1,506 @@ + + + + + + + +

Allocation profile

+
  
+
Produced by async-profiler
+ +
+

+

Matched:

+ diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/report2/asyncprof/prof_64_cpu_get.html b/src/main/java/ru/vk/itmo/test/osipovdaniil/report2/asyncprof/prof_64_cpu_get.html new file mode 100644 index 000000000..0c884b61f --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/report2/asyncprof/prof_64_cpu_get.html @@ -0,0 +1,1838 @@ + + + + + + + +

CPU profile

+
  
+
Produced by async-profiler
+ +
+

+

Matched:

+ diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/report2/asyncprof/prof_64_cpu_put.html b/src/main/java/ru/vk/itmo/test/osipovdaniil/report2/asyncprof/prof_64_cpu_put.html new file mode 100644 index 000000000..cb0101c0a --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/report2/asyncprof/prof_64_cpu_put.html @@ -0,0 +1,2284 @@ + + + + + + + +

CPU profile

+
  
+
Produced by async-profiler
+ +
+

+

Matched:

+ diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/report2/asyncprof/prof_64_lock_get.html b/src/main/java/ru/vk/itmo/test/osipovdaniil/report2/asyncprof/prof_64_lock_get.html new file mode 100644 index 000000000..12b36acc3 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/report2/asyncprof/prof_64_lock_get.html @@ -0,0 +1,336 @@ + + + + + + + +

Lock profile

+
  
+
Produced by async-profiler
+ +
+

+

Matched:

+ diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/report2/asyncprof/prof_64_lock_put.html b/src/main/java/ru/vk/itmo/test/osipovdaniil/report2/asyncprof/prof_64_lock_put.html new file mode 100644 index 000000000..6d269cb13 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/report2/asyncprof/prof_64_lock_put.html @@ -0,0 +1,356 @@ + + + + + + + +

Lock profile

+
  
+
Produced by async-profiler
+ +
+

+

Matched:

+ diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/report2/graphics/percentiles.png b/src/main/java/ru/vk/itmo/test/osipovdaniil/report2/graphics/percentiles.png new file mode 100644 index 0000000000000000000000000000000000000000..67182f0cf9cf3ab6770119cf69ce9103cddab850 GIT binary patch literal 152055 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
v;s6W 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

kzZPlCoP&`Uq;Bal7{Kfd3<8#3?4Elr7E;En34 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

%gv)p#5*Aud z?!+h@EY$p5_(2=e?zKqGpp!H-vIqfo)mB0owb`Dp6w~9J91$`H3$IrnwVrrqTA<`G zx9w(EM|-Z>(9);#22Jt0Pf|auY%oErfOybZD!T;nQ^Vk?XKB*OJ!H;M>|T%&L? zm0DR!DeKZMa!qYGmzLccbXdQ)&LHrme*mc5NemIM&({J6jR)=gUmY~BwN&G^d3dL& z!y&M(Y;nScpX(2YI^!@0hEY*{`h`j~^ML#=qz_iBw@8k8GE^s!i zX{_!2{tiiqj(b;4L3mox{1@vll;&mY%>8yfPsZQFDet8-Ay#y15ThAdyWwH6W~kF6 z-FroNn1uBbK7ugND`yqWvBG`^Z`bf)5H~X_hk)P6Ov@LJmAaW5HY4xJuqqSUjDs6* z(edsLYN51PUc3{nD=qnHzW>Ri>BZLLL$5vVjt9xA2X3`^d3uxc7~}pWbpI)-mbSeY zBrX_s9z+{Lh$(_+7OBYL1Uxl^Fu;hYog*y#CorP40KAkpjlK&N_lEB46fR#g7(3t5 za`@%3yB2B`TrEqdD|5e=cERaZEO);aR$MmQ-t!S{!;*2ibc`Fkgj>BmHevH{6Xrju z8{_kGhVybZl*SUY1ir$OaVjQAniN1(TabY~JVJ~s>_o+(9D@&3s2!%o>;8m{>Juy_ zfH!SSA30)l=?E=d((i;VG|xfzmv}67X1to5A(pl}`DO;PONte~>M%E`P&}b-u+Il8 z@kwf%_cfCVk8ul|lg9}G38H*<_n?-YAK%styt!3QX+3wqt9)ba z62-K)c4DcA&iu7S!-1jWR}LiccitS;5#Q2eXt9YyA}RBr3L1H_UQI7%#7S#uLlQ=W zR2YKd_=v<|v}elnpzuOYC1Gli%1&5NQiQ2*upkZ#Id_xr-Gqh2p9^1)#5=@{Q_%t< zsood!+fC+BfkRD~ACz)ejI6W+iOlfboo&9u6}QUE19iNp=ed&cq>yLM$lZNfYp=pZSn&TLOICxxS)6A(3d18nD=DT@zm1PsNnT%d^kp8i`P4xU)CaWi1<*o557$sTym$fJRG2iHCyrbk5L?qdUKZ}X9mj*OH-YE zXN3>CDzm+;<(3HHm=<$7#d^O_N*9sEP{FXtEHTx1hS%-Oo1Ib7#_xks$>Ev>U ze;b5a!v?p0#vR^2yMs`+SXq|sqehcJXF5DQ5SJNc-AYhzSAcmPpx&~eBP9)G6!bD8 z#Y|ODdnW(h*A1XPy~NfIT&KueTJG&U!zj0FtE^;J!zGKNIUnmuntH!#F7E_Mf%6z6 zFm+$p#v%FIhH%_m97AZzOg; z4PWQHwJM)#?6sS4>J=HQfS<Cv=q)LkHg0O1e0As85CwUps9!|0O5)D z^d}c|PzB1(n^di>SQ{#c`u4(&iug>kK~0IXZcXEwzydm+i?jNzQ(q?v!YwnW@62|( zo0q*d41E@vdjnq#cdF#?rc3)`xzIMjgw%k9!{Xxjl=3#?!5f=RxP=4!I`&rOY#11BitV z{s^2)4m`1h^h8h)!N)0_E?ot?Pv1c`e_vD2j_>Mm2uN==?Zetc6#~+lH)dp`v>yV} z@~a2&=_bP=_Uq@Mg4l3KpJ`4|nxh@Iqd(bCAz?n9e|WxVByeza-Z;IhvA>ePNtg?WaaT;J>ZZZlXhYUDt+h4Z%2CkG$%S=jmj|1$cUQ9 ze%s8{NmZ?V0MPpz8bY07e=n-7$xi9fz?$B$LP`1T}c(s%LAWZc*c z_BZElGVXNpl$Vp3a+qEmZ~T5(2sxFE2kJcqP&P$|EoXIM{MW)oKDd}On9zTJXVN&O z#el7Cr=ecap%ItKTemDU;8gqUMhmZy83t? z$0kZ(MwOCU@FNERCKwbw<%Uf^4+uHW)G($>+ieRTe zRiC(GYtK5%v7_sr$48y_&XezBt(QeuN(SOWpH^-X!_II&t(rKoCbSNEl0j_+C#Qn# zqfB-z>UCh2>i!^)^p*k-UW%xJSxcXV01^^1UBIsr1+Nm7n1aSg)oMU6y6UPVVA`o?4Y&TB

~+xff!sL@EO{P#Qmz7-hX}O#}kKJg`GSV^S~+m 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 H?>YJ3F_J(W literal 0 HcmV?d00001 diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/report2/report2.md b/src/main/java/ru/vk/itmo/test/osipovdaniil/report2/report2.md new file mode 100644 index 000000000..0b5db200b --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/report2/report2.md @@ -0,0 +1,28 @@ +# Отчёт по 2 стэйджу + +## wrk + +Стоит отметить небольшое ухудшение работы при 1 коннекшене при добавлении `ExecutorService` по сравнении с его отсутсвием.
+В тоже время при 64 и 128 коннекшенах наблюдается стабильная работа с маленькими задержками. +![percentiles](/home/sbread/Desktop/labs/HLS/2024-highload-dht/src/main/java/ru/vk/itmo/test/osipovdaniil/report2/graphics/percentiles.png) + +[detailed wrk 64 connections][1].
+[detailed wrk 128 connections][2]. + +[1]: /home/sbread/Desktop/labs/HLS/2024-highload-dht/src/main/java/ru/vk/itmo/test/osipovdaniil/report2/wrk/wrk:78 +[2]: /home/sbread/Desktop/labs/HLS/2024-highload-dht/src/main/java/ru/vk/itmo/test/osipovdaniil/report2/wrk/wrk:453 + +## asyncprof + +[detailed profiling in this folder][3] + +[3]: /home/sbread/Desktop/labs/HLS/2024-highload-dht/src/main/java/ru/vk/itmo/test/osipovdaniil/report2/asyncprof + +Основные тенденции не меняются, однако появляются дополнительные расходы как в cpu, так и аллокациях (примерно 10%), +связанных с `ExecutorService`. + +### lock + +Распределение lock'ов везде схожее и почти не меняется при разнов количестве коннекшенов. +Так примерно 25-30% времени это lock на очередь, 60% lock на ожидание завершения таски, 5-10% на обработку запроса, а оставшееся уходит на `SelectorThread` + diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/report2/wrk/wrk b/src/main/java/ru/vk/itmo/test/osipovdaniil/report2/wrk/wrk new file mode 100644 index 000000000..a16b6a943 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/report2/wrk/wrk @@ -0,0 +1,724 @@ +./wrk -d 30 -t 1 -c 1 -R 16000 -L -s /home/sbread/Desktop/labs/HLS/2024-highload-dht/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/put.lua http://localhost:8080 +Running 30s test @ http://localhost:8080 + 1 threads and 1 connections + Thread calibration: mean lat.: 867.675ms, rate sampling interval: 2844ms + Thread Stats Avg Stdev Max +/- Stdev + Latency 2.56s 834.13ms 4.26s 61.49% + Req/Sec 13.80k 0.90k 14.99k 42.86% + Latency Distribution (HdrHistogram - Recorded Latency) + 50.000% 2.42s + 75.000% 3.13s + 90.000% 3.94s + 99.000% 4.22s + 99.900% 4.26s + 99.990% 4.26s + 99.999% 4.26s +100.000% 4.26s + + Detailed Percentile spectrum: + Value Percentile TotalCount 1/(1-Percentile) + + 1491.967 0.000000 235 1.00 + 1547.263 0.100000 27988 1.11 + 1768.447 0.200000 55297 1.25 + 1890.303 0.300000 83925 1.43 + 2060.287 0.400000 110878 1.67 + 2424.831 0.500000 137949 2.00 + 2627.583 0.550000 151753 2.22 + 2744.319 0.600000 165490 2.50 + 2891.775 0.650000 179595 2.86 + 2957.311 0.700000 194122 3.33 + 3129.343 0.750000 206835 4.00 + 3274.751 0.775000 213945 4.44 + 3397.631 0.800000 220688 5.00 + 3504.127 0.825000 227519 5.71 + 3586.047 0.850000 234619 6.67 + 3753.983 0.875000 241317 8.00 + 3854.335 0.887500 244766 8.89 + 3944.447 0.900000 248204 10.00 + 4014.079 0.912500 251660 11.43 + 4067.327 0.925000 255130 13.33 + 4093.951 0.937500 259173 16.00 + 4095.999 0.943750 260512 17.78 + 4112.383 0.950000 262290 20.00 + 4118.527 0.956250 263913 22.86 + 4124.671 0.962500 265849 26.67 + 4128.767 0.968750 267371 32.00 + 4130.815 0.971875 268189 35.56 + 4134.911 0.975000 268995 40.00 + 4145.151 0.978125 269748 45.71 + 4171.775 0.981250 270653 53.33 + 4192.255 0.984375 271522 64.00 + 4198.399 0.985938 271904 71.11 + 4206.591 0.987500 272436 80.00 + 4214.783 0.989062 272894 91.43 + 4222.975 0.990625 273333 106.67 + 4231.167 0.992188 273779 128.00 + 4235.263 0.992969 273999 142.22 + 4239.359 0.993750 274220 160.00 + 4243.455 0.994531 274423 182.86 + 4247.551 0.995313 274607 213.33 + 4251.647 0.996094 274813 256.00 + 4251.647 0.996484 274813 284.44 + 4255.743 0.996875 274994 320.00 + 4259.839 0.997266 275103 365.71 + 4263.935 0.997656 275779 426.67 + 4263.935 1.000000 275779 inf +#[Mean = 2560.818, StdDeviation = 834.130] +#[Max = 4259.840, Total count = 275779] +#[Buckets = 27, SubBuckets = 2048] +---------------------------------------------------------- + 411815 requests in 30.00s, 26.31MB read +Requests/sec: 13727.23 +Transfer/sec: 0.88MB + +-------------------------------------------------------------------------------------- + +./wrk -d 30 -t 1 -c 64 -R 16000 -L -s /home/sbread/Desktop/labs/HLS/2024-highload-dht/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/put.lua http://localhost:8080 +Running 30s test @ http://localhost:8080 + 1 threads and 64 connections + Thread calibration: mean lat.: 2.368ms, rate sampling interval: 10ms + Thread Stats Avg Stdev Max +/- Stdev + Latency 2.38ms 703.85us 8.97ms 70.60% + Req/Sec 16.90k 2.91k 23.11k 51.09% + Latency Distribution (HdrHistogram - Recorded Latency) + 50.000% 2.33ms + 75.000% 2.87ms + 90.000% 3.29ms + 99.000% 3.96ms + 99.900% 5.22ms + 99.990% 7.66ms + 99.999% 8.81ms +100.000% 8.98ms + + Detailed Percentile spectrum: + Value Percentile TotalCount 1/(1-Percentile) + + 0.107 0.000000 1 1.00 + 1.599 0.100000 31580 1.11 + 1.827 0.200000 63027 1.25 + 1.996 0.300000 94500 1.43 + 2.159 0.400000 126259 1.67 + 2.331 0.500000 157558 2.00 + 2.427 0.550000 173204 2.22 + 2.531 0.600000 188995 2.50 + 2.641 0.650000 204737 2.86 + 2.755 0.700000 220581 3.33 + 2.873 0.750000 236216 4.00 + 2.935 0.775000 244158 4.44 + 2.999 0.800000 252077 5.00 + 3.065 0.825000 259886 5.71 + 3.133 0.850000 267723 6.67 + 3.205 0.875000 275577 8.00 + 3.243 0.887500 279435 8.89 + 3.285 0.900000 283418 10.00 + 3.331 0.912500 287436 11.43 + 3.379 0.925000 291267 13.33 + 3.437 0.937500 295222 16.00 + 3.469 0.943750 297182 17.78 + 3.503 0.950000 299124 20.00 + 3.543 0.956250 301128 22.86 + 3.589 0.962500 303102 26.67 + 3.643 0.968750 305032 32.00 + 3.675 0.971875 306014 35.56 + 3.709 0.975000 306995 40.00 + 3.747 0.978125 307980 45.71 + 3.791 0.981250 308950 53.33 + 3.843 0.984375 309950 64.00 + 3.873 0.985938 310447 71.11 + 3.905 0.987500 310917 80.00 + 3.941 0.989062 311432 91.43 + 3.985 0.990625 311924 106.67 + 4.033 0.992188 312410 128.00 + 4.059 0.992969 312655 142.22 + 4.095 0.993750 312891 160.00 + 4.135 0.994531 313140 182.86 + 4.183 0.995313 313393 213.33 + 4.247 0.996094 313633 256.00 + 4.287 0.996484 313747 284.44 + 4.335 0.996875 313874 320.00 + 4.395 0.997266 313992 365.71 + 4.483 0.997656 314114 426.67 + 4.643 0.998047 314237 512.00 + 4.747 0.998242 314299 568.89 + 4.851 0.998437 314363 640.00 + 4.963 0.998633 314421 731.43 + 5.079 0.998828 314483 853.33 + 5.223 0.999023 314546 1024.00 + 5.307 0.999121 314575 1137.78 + 5.427 0.999219 314609 1280.00 + 5.563 0.999316 314636 1462.86 + 5.731 0.999414 314668 1706.67 + 5.899 0.999512 314698 2048.00 + 5.995 0.999561 314713 2275.56 + 6.087 0.999609 314729 2560.00 + 6.211 0.999658 314744 2925.71 + 6.355 0.999707 314759 3413.33 + 6.507 0.999756 314775 4096.00 + 6.575 0.999780 314782 4551.11 + 6.691 0.999805 314790 5120.00 + 6.843 0.999829 314798 5851.43 + 7.011 0.999854 314805 6826.67 + 7.367 0.999878 314813 8192.00 + 7.455 0.999890 314817 9102.22 + 7.711 0.999902 314821 10240.00 + 7.883 0.999915 314825 11702.86 + 7.927 0.999927 314828 13653.33 + 8.087 0.999939 314832 16384.00 + 8.103 0.999945 314834 18204.44 + 8.127 0.999951 314836 20480.00 + 8.163 0.999957 314839 23405.71 + 8.199 0.999963 314840 27306.67 + 8.335 0.999969 314842 32768.00 + 8.407 0.999973 314843 36408.89 + 8.431 0.999976 314844 40960.00 + 8.455 0.999979 314845 46811.43 + 8.535 0.999982 314846 54613.33 + 8.607 0.999985 314847 65536.00 + 8.607 0.999986 314847 72817.78 + 8.815 0.999988 314848 81920.00 + 8.815 0.999989 314848 93622.86 + 8.871 0.999991 314849 109226.67 + 8.871 0.999992 314849 131072.00 + 8.871 0.999993 314849 145635.56 + 8.887 0.999994 314850 163840.00 + 8.887 0.999995 314850 187245.71 + 8.887 0.999995 314850 218453.33 + 8.887 0.999996 314850 262144.00 + 8.887 0.999997 314850 291271.11 + 8.975 0.999997 314851 327680.00 + 8.975 1.000000 314851 inf +#[Mean = 2.382, StdDeviation = 0.704] +#[Max = 8.968, Total count = 314851] +#[Buckets = 27, SubBuckets = 2048] +---------------------------------------------------------- + 463992 requests in 30.00s, 29.65MB read +Requests/sec: 15466.30 +Transfer/sec: 0.99MB + +---------------------------------------------------------------------------------------------- + +./wrk -d 30 -t 1 -c 64 -R 16000 -L -s /home/sbread/Desktop/labs/HLS/2024-highload-dht/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/get.lua http://localhost:8080 +Running 30s test @ http://localhost:8080 + 1 threads and 64 connections + Thread calibration: mean lat.: 2.254ms, rate sampling interval: 10ms + Thread Stats Avg Stdev Max +/- Stdev + Latency 2.27ms 1.01ms 7.43ms 67.81% + Req/Sec 16.90k 2.17k 24.11k 65.04% + Latency Distribution (HdrHistogram - Recorded Latency) + 50.000% 2.13ms + 75.000% 2.90ms + 90.000% 3.76ms + 99.000% 4.82ms + 99.900% 5.41ms + 99.990% 5.96ms + 99.999% 7.14ms +100.000% 7.43ms + + Detailed Percentile spectrum: + Value Percentile TotalCount 1/(1-Percentile) + + 0.220 0.000000 1 1.00 + 1.076 0.100000 31494 1.11 + 1.384 0.200000 63042 1.25 + 1.634 0.300000 94528 1.43 + 1.880 0.400000 125978 1.67 + 2.129 0.500000 157713 2.00 + 2.247 0.550000 173253 2.22 + 2.373 0.600000 189138 2.50 + 2.515 0.650000 204709 2.86 + 2.693 0.700000 220480 3.33 + 2.901 0.750000 236207 4.00 + 3.015 0.775000 244172 4.44 + 3.129 0.800000 251965 5.00 + 3.249 0.825000 259901 5.71 + 3.381 0.850000 267710 6.67 + 3.551 0.875000 275587 8.00 + 3.649 0.887500 279492 8.89 + 3.757 0.900000 283470 10.00 + 3.873 0.912500 287404 11.43 + 3.987 0.925000 291332 13.33 + 4.093 0.937500 295274 16.00 + 4.147 0.943750 297299 17.78 + 4.203 0.950000 299281 20.00 + 4.263 0.956250 301235 22.86 + 4.327 0.962500 303170 26.67 + 4.399 0.968750 305113 32.00 + 4.439 0.971875 306070 35.56 + 4.487 0.975000 307094 40.00 + 4.535 0.978125 308054 45.71 + 4.591 0.981250 309060 53.33 + 4.655 0.984375 309998 64.00 + 4.691 0.985938 310500 71.11 + 4.735 0.987500 311020 80.00 + 4.783 0.989062 311513 91.43 + 4.839 0.990625 311989 106.67 + 4.899 0.992188 312491 128.00 + 4.931 0.992969 312709 142.22 + 4.967 0.993750 312958 160.00 + 5.003 0.994531 313199 182.86 + 5.039 0.995313 313445 213.33 + 5.079 0.996094 313692 256.00 + 5.103 0.996484 313817 284.44 + 5.131 0.996875 313948 320.00 + 5.163 0.997266 314062 365.71 + 5.195 0.997656 314188 426.67 + 5.235 0.998047 314307 512.00 + 5.263 0.998242 314369 568.89 + 5.295 0.998437 314428 640.00 + 5.331 0.998633 314495 731.43 + 5.371 0.998828 314554 853.33 + 5.411 0.999023 314615 1024.00 + 5.439 0.999121 314648 1137.78 + 5.467 0.999219 314678 1280.00 + 5.495 0.999316 314705 1462.86 + 5.535 0.999414 314734 1706.67 + 5.599 0.999512 314770 2048.00 + 5.615 0.999561 314781 2275.56 + 5.635 0.999609 314797 2560.00 + 5.655 0.999658 314811 2925.71 + 5.675 0.999707 314825 3413.33 + 5.723 0.999756 314841 4096.00 + 5.747 0.999780 314848 4551.11 + 5.771 0.999805 314857 5120.00 + 5.799 0.999829 314865 5851.43 + 5.855 0.999854 314871 6826.67 + 5.927 0.999878 314879 8192.00 + 5.947 0.999890 314883 9102.22 + 5.975 0.999902 314887 10240.00 + 6.035 0.999915 314892 11702.86 + 6.075 0.999927 314894 13653.33 + 6.103 0.999939 314899 16384.00 + 6.187 0.999945 314900 18204.44 + 6.307 0.999951 314902 20480.00 + 6.367 0.999957 314904 23405.71 + 6.483 0.999963 314906 27306.67 + 6.783 0.999969 314908 32768.00 + 6.891 0.999973 314909 36408.89 + 6.919 0.999976 314910 40960.00 + 6.923 0.999979 314911 46811.43 + 6.963 0.999982 314913 54613.33 + 6.963 0.999985 314913 65536.00 + 6.963 0.999986 314913 72817.78 + 7.143 0.999988 314914 81920.00 + 7.143 0.999989 314914 93622.86 + 7.159 0.999991 314915 109226.67 + 7.159 0.999992 314915 131072.00 + 7.159 0.999993 314915 145635.56 + 7.243 0.999994 314916 163840.00 + 7.243 0.999995 314916 187245.71 + 7.243 0.999995 314916 218453.33 + 7.243 0.999996 314916 262144.00 + 7.243 0.999997 314916 291271.11 + 7.431 0.999997 314917 327680.00 + 7.431 1.000000 314917 inf +#[Mean = 2.267, StdDeviation = 1.009] +#[Max = 7.428, Total count = 314917] +#[Buckets = 27, SubBuckets = 2048] +---------------------------------------------------------- + 477486 requests in 30.00s, 33.52MB read + Non-2xx or 3xx responses: 13486 +Requests/sec: 15915.83 +Transfer/sec: 1.12MB + +--------------------------------------------------------------------------------- + +./wrk -d 30 -t 1 -c 64 -R 16000 -L -s /home/sbread/Desktop/labs/HLS/2024-highload-dht/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/get.lua http://localhost:8080 +Running 30s test @ http://localhost:8080 + 1 threads and 64 connections + Thread calibration: mean lat.: 2.230ms, rate sampling interval: 10ms + Thread Stats Avg Stdev Max +/- Stdev + Latency 2.24ms 0.98ms 6.04ms 67.41% + Req/Sec 16.90k 2.15k 23.89k 64.74% + Latency Distribution (HdrHistogram - Recorded Latency) + 50.000% 2.12ms + 75.000% 2.87ms + 90.000% 3.66ms + 99.000% 4.74ms + 99.900% 5.34ms + 99.990% 5.76ms + 99.999% 5.97ms +100.000% 6.05ms + + Detailed Percentile spectrum: + Value Percentile TotalCount 1/(1-Percentile) + + 0.169 0.000000 1 1.00 + 1.058 0.100000 31494 1.11 + 1.381 0.200000 62978 1.25 + 1.642 0.300000 94557 1.43 + 1.879 0.400000 126093 1.67 + 2.117 0.500000 157634 2.00 + 2.239 0.550000 173365 2.22 + 2.371 0.600000 189148 2.50 + 2.515 0.650000 204672 2.86 + 2.681 0.700000 220429 3.33 + 2.865 0.750000 236185 4.00 + 2.965 0.775000 244127 4.44 + 3.071 0.800000 252027 5.00 + 3.191 0.825000 259855 5.71 + 3.321 0.850000 267769 6.67 + 3.475 0.875000 275543 8.00 + 3.563 0.887500 279514 8.89 + 3.661 0.900000 283434 10.00 + 3.767 0.912500 287336 11.43 + 3.879 0.925000 291276 13.33 + 3.995 0.937500 295248 16.00 + 4.055 0.943750 297206 17.78 + 4.115 0.950000 299210 20.00 + 4.179 0.956250 301236 22.86 + 4.243 0.962500 303079 26.67 + 4.319 0.968750 305078 32.00 + 4.363 0.971875 306107 35.56 + 4.407 0.975000 307066 40.00 + 4.455 0.978125 308062 45.71 + 4.511 0.981250 309019 53.33 + 4.579 0.984375 309996 64.00 + 4.619 0.985938 310484 71.11 + 4.663 0.987500 310981 80.00 + 4.707 0.989062 311454 91.43 + 4.759 0.990625 311949 106.67 + 4.819 0.992188 312437 128.00 + 4.855 0.992969 312682 142.22 + 4.891 0.993750 312918 160.00 + 4.931 0.994531 313184 182.86 + 4.971 0.995313 313411 213.33 + 5.023 0.996094 313654 256.00 + 5.051 0.996484 313792 284.44 + 5.079 0.996875 313908 320.00 + 5.107 0.997266 314020 365.71 + 5.147 0.997656 314152 426.67 + 5.187 0.998047 314273 512.00 + 5.211 0.998242 314339 568.89 + 5.235 0.998437 314396 640.00 + 5.267 0.998633 314454 731.43 + 5.307 0.998828 314513 853.33 + 5.343 0.999023 314572 1024.00 + 5.363 0.999121 314604 1137.78 + 5.383 0.999219 314638 1280.00 + 5.411 0.999316 314664 1462.86 + 5.447 0.999414 314696 1706.67 + 5.483 0.999512 314727 2048.00 + 5.507 0.999561 314741 2275.56 + 5.531 0.999609 314758 2560.00 + 5.543 0.999658 314773 2925.71 + 5.563 0.999707 314788 3413.33 + 5.599 0.999756 314803 4096.00 + 5.619 0.999780 314812 4551.11 + 5.635 0.999805 314819 5120.00 + 5.659 0.999829 314828 5851.43 + 5.683 0.999854 314833 6826.67 + 5.723 0.999878 314841 8192.00 + 5.739 0.999890 314845 9102.22 + 5.763 0.999902 314850 10240.00 + 5.771 0.999915 314854 11702.86 + 5.783 0.999927 314856 13653.33 + 5.795 0.999939 314860 16384.00 + 5.815 0.999945 314862 18204.44 + 5.847 0.999951 314864 20480.00 + 5.879 0.999957 314866 23405.71 + 5.883 0.999963 314869 27306.67 + 5.899 0.999969 314872 32768.00 + 5.899 0.999973 314872 36408.89 + 5.899 0.999976 314872 40960.00 + 5.931 0.999979 314874 46811.43 + 5.931 0.999982 314874 54613.33 + 5.975 0.999985 314876 65536.00 + 5.975 0.999986 314876 72817.78 + 5.975 0.999988 314876 81920.00 + 5.975 0.999989 314876 93622.86 + 6.011 0.999991 314877 109226.67 + 6.011 0.999992 314877 131072.00 + 6.011 0.999993 314877 145635.56 + 6.035 0.999994 314878 163840.00 + 6.035 0.999995 314878 187245.71 + 6.035 0.999995 314878 218453.33 + 6.035 0.999996 314878 262144.00 + 6.035 0.999997 314878 291271.11 + 6.047 0.999997 314879 327680.00 + 6.047 1.000000 314879 inf +#[Mean = 2.245, StdDeviation = 0.983] +#[Max = 6.044, Total count = 314879] +#[Buckets = 27, SubBuckets = 2048] +---------------------------------------------------------- + 477483 requests in 30.00s, 33.52MB read + Non-2xx or 3xx responses: 13483 +Requests/sec: 15915.44 +Transfer/sec: 1.12MB + +---------------------------------------------------------------------------------------- + + +./wrk -d 120 -t 1 -c 128 -R 16000 -L -s /home/sbread/Desktop/labs/HLS/2024-highload-dht/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/put.lua http://localhost:8080 +Running 2m test @ http://localhost:8080 + 1 threads and 128 connections + Thread calibration: mean lat.: 4.980ms, rate sampling interval: 14ms + Thread Stats Avg Stdev Max +/- Stdev + Latency 4.96ms 1.54ms 16.06ms 70.30% + Req/Sec 16.54k 777.20 22.23k 79.02% + Latency Distribution (HdrHistogram - Recorded Latency) + 50.000% 4.89ms + 75.000% 6.00ms + 90.000% 7.01ms + 99.000% 8.41ms + 99.900% 9.38ms + 99.990% 13.25ms + 99.999% 15.04ms +100.000% 16.06ms + + Detailed Percentile spectrum: + Value Percentile TotalCount 1/(1-Percentile) + + 0.189 0.000000 1 1.00 + 3.265 0.100000 175160 1.11 + 3.661 0.200000 350037 1.25 + 4.049 0.300000 525158 1.43 + 4.471 0.400000 700545 1.67 + 4.891 0.500000 875724 2.00 + 5.103 0.550000 962878 2.22 + 5.315 0.600000 1050105 2.50 + 5.535 0.650000 1138814 2.86 + 5.759 0.700000 1224954 3.33 + 5.999 0.750000 1313228 4.00 + 6.123 0.775000 1357015 4.44 + 6.259 0.800000 1400935 5.00 + 6.411 0.825000 1444290 5.71 + 6.587 0.850000 1487464 6.67 + 6.791 0.875000 1531489 8.00 + 6.899 0.887500 1553019 8.89 + 7.011 0.900000 1574923 10.00 + 7.131 0.912500 1596927 11.43 + 7.259 0.925000 1618670 13.33 + 7.411 0.937500 1640809 16.00 + 7.495 0.943750 1651517 17.78 + 7.591 0.950000 1662727 20.00 + 7.687 0.956250 1673336 22.86 + 7.791 0.962500 1684251 26.67 + 7.907 0.968750 1695339 32.00 + 7.963 0.971875 1700631 35.56 + 8.023 0.975000 1706301 40.00 + 8.083 0.978125 1711512 45.71 + 8.155 0.981250 1716984 53.33 + 8.239 0.984375 1722658 64.00 + 8.279 0.985938 1725167 71.11 + 8.327 0.987500 1728026 80.00 + 8.375 0.989062 1730846 91.43 + 8.423 0.990625 1733382 106.67 + 8.479 0.992188 1736322 128.00 + 8.503 0.992969 1737499 142.22 + 8.535 0.993750 1738830 160.00 + 8.575 0.994531 1740390 182.86 + 8.615 0.995313 1741661 213.33 + 8.663 0.996094 1742934 256.00 + 8.703 0.996484 1743706 284.44 + 8.743 0.996875 1744421 320.00 + 8.783 0.997266 1745067 365.71 + 8.831 0.997656 1745702 426.67 + 8.903 0.998047 1746394 512.00 + 8.943 0.998242 1746698 568.89 + 9.015 0.998437 1747056 640.00 + 9.095 0.998633 1747368 731.43 + 9.215 0.998828 1747717 853.33 + 9.415 0.999023 1748057 1024.00 + 9.575 0.999121 1748226 1137.78 + 9.759 0.999219 1748393 1280.00 + 9.943 0.999316 1748569 1462.86 + 10.111 0.999414 1748738 1706.67 + 10.383 0.999512 1748906 2048.00 + 10.591 0.999561 1748994 2275.56 + 10.855 0.999609 1749080 2560.00 + 11.071 0.999658 1749163 2925.71 + 11.311 0.999707 1749249 3413.33 + 11.791 0.999756 1749335 4096.00 + 12.007 0.999780 1749377 4551.11 + 12.239 0.999805 1749421 5120.00 + 12.503 0.999829 1749463 5851.43 + 12.727 0.999854 1749504 6826.67 + 12.975 0.999878 1749547 8192.00 + 13.095 0.999890 1749568 9102.22 + 13.287 0.999902 1749590 10240.00 + 13.463 0.999915 1749611 11702.86 + 13.639 0.999927 1749633 13653.33 + 13.847 0.999939 1749656 16384.00 + 13.975 0.999945 1749664 18204.44 + 14.063 0.999951 1749675 20480.00 + 14.167 0.999957 1749686 23405.71 + 14.279 0.999963 1749696 27306.67 + 14.423 0.999969 1749707 32768.00 + 14.479 0.999973 1749712 36408.89 + 14.551 0.999976 1749718 40960.00 + 14.607 0.999979 1749723 46811.43 + 14.743 0.999982 1749728 54613.33 + 14.791 0.999985 1749734 65536.00 + 14.799 0.999986 1749736 72817.78 + 14.903 0.999988 1749739 81920.00 + 14.999 0.999989 1749742 93622.86 + 15.047 0.999991 1749745 109226.67 + 15.159 0.999992 1749747 131072.00 + 15.199 0.999993 1749749 145635.56 + 15.223 0.999994 1749750 163840.00 + 15.247 0.999995 1749751 187245.71 + 15.279 0.999995 1749752 218453.33 + 15.495 0.999996 1749754 262144.00 + 15.495 0.999997 1749754 291271.11 + 15.543 0.999997 1749755 327680.00 + 15.575 0.999997 1749756 374491.43 + 15.575 0.999998 1749756 436906.67 + 15.647 0.999998 1749757 524288.00 + 15.647 0.999998 1749757 582542.22 + 15.679 0.999998 1749758 655360.00 + 15.679 0.999999 1749758 748982.86 + 15.679 0.999999 1749758 873813.33 + 15.919 0.999999 1749759 1048576.00 + 15.919 0.999999 1749759 1165084.44 + 15.919 0.999999 1749759 1310720.00 + 15.919 0.999999 1749759 1497965.71 + 15.919 0.999999 1749759 1747626.67 + 16.063 1.000000 1749760 2097152.00 + 16.063 1.000000 1749760 inf +#[Mean = 4.959, StdDeviation = 1.537] +#[Max = 16.056, Total count = 1749760] +#[Buckets = 27, SubBuckets = 2048] +---------------------------------------------------------- + 1904000 requests in 2.00m, 121.66MB read +Requests/sec: 15866.39 +Transfer/sec: 1.01MB + +--------------------------------------------------------------------- + +./wrk -d 120 -t 1 -c 128 -R 16000 -L -s /home/sbread/Desktop/labs/HLS/2024-highload-dht/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/get.lua http://localhost:8080 +Running 2m test @ http://localhost:8080 + 1 threads and 128 connections + Thread calibration: mean lat.: 4.159ms, rate sampling interval: 11ms + Thread Stats Avg Stdev Max +/- Stdev + Latency 4.15ms 1.36ms 12.44ms 68.83% + Req/Sec 16.73k 2.57k 27.20k 68.19% + Latency Distribution (HdrHistogram - Recorded Latency) + 50.000% 4.08ms + 75.000% 5.03ms + 90.000% 5.88ms + 99.000% 7.78ms + 99.900% 9.07ms + 99.990% 10.04ms + 99.999% 11.14ms +100.000% 12.45ms + + Detailed Percentile spectrum: + Value Percentile TotalCount 1/(1-Percentile) + + 0.283 0.000000 1 1.00 + 2.449 0.100000 175311 1.11 + 2.993 0.200000 350684 1.25 + 3.391 0.300000 525583 1.43 + 3.747 0.400000 700447 1.67 + 4.083 0.500000 875247 2.00 + 4.255 0.550000 964167 2.22 + 4.431 0.600000 1050384 2.50 + 4.619 0.650000 1137743 2.86 + 4.819 0.700000 1226399 3.33 + 5.027 0.750000 1313005 4.00 + 5.143 0.775000 1357452 4.44 + 5.263 0.800000 1399921 5.00 + 5.399 0.825000 1443917 5.71 + 5.543 0.850000 1487589 6.67 + 5.703 0.875000 1531825 8.00 + 5.787 0.887500 1552911 8.89 + 5.883 0.900000 1574814 10.00 + 5.995 0.912500 1597335 11.43 + 6.119 0.925000 1618741 13.33 + 6.263 0.937500 1640440 16.00 + 6.347 0.943750 1651720 17.78 + 6.431 0.950000 1662225 20.00 + 6.531 0.956250 1673295 22.86 + 6.647 0.962500 1684138 26.67 + 6.803 0.968750 1695171 32.00 + 6.903 0.971875 1700699 35.56 + 7.011 0.975000 1706024 40.00 + 7.139 0.978125 1711554 45.71 + 7.275 0.981250 1716976 53.33 + 7.431 0.984375 1722418 64.00 + 7.515 0.985938 1725111 71.11 + 7.607 0.987500 1727846 80.00 + 7.711 0.989062 1730604 91.43 + 7.831 0.990625 1733370 106.67 + 7.967 0.992188 1736076 128.00 + 8.043 0.992969 1737419 142.22 + 8.131 0.993750 1738823 160.00 + 8.223 0.994531 1740223 182.86 + 8.311 0.995313 1741531 213.33 + 8.415 0.996094 1742928 256.00 + 8.471 0.996484 1743610 284.44 + 8.535 0.996875 1744330 320.00 + 8.599 0.997266 1744999 365.71 + 8.671 0.997656 1745629 426.67 + 8.759 0.998047 1746310 512.00 + 8.815 0.998242 1746684 568.89 + 8.871 0.998437 1747020 640.00 + 8.927 0.998633 1747320 731.43 + 8.999 0.998828 1747665 853.33 + 9.087 0.999023 1748033 1024.00 + 9.135 0.999121 1748192 1137.78 + 9.175 0.999219 1748349 1280.00 + 9.239 0.999316 1748531 1462.86 + 9.295 0.999414 1748691 1706.67 + 9.375 0.999512 1748877 2048.00 + 9.407 0.999561 1748957 2275.56 + 9.447 0.999609 1749028 2560.00 + 9.495 0.999658 1749113 2925.71 + 9.567 0.999707 1749204 3413.33 + 9.639 0.999756 1749288 4096.00 + 9.687 0.999780 1749328 4551.11 + 9.735 0.999805 1749373 5120.00 + 9.799 0.999829 1749419 5851.43 + 9.863 0.999854 1749454 6826.67 + 9.951 0.999878 1749500 8192.00 + 10.007 0.999890 1749520 9102.22 + 10.071 0.999902 1749542 10240.00 + 10.111 0.999915 1749561 11702.86 + 10.199 0.999927 1749582 13653.33 + 10.279 0.999939 1749605 16384.00 + 10.335 0.999945 1749616 18204.44 + 10.399 0.999951 1749626 20480.00 + 10.447 0.999957 1749640 23405.71 + 10.503 0.999963 1749646 27306.67 + 10.647 0.999969 1749657 32768.00 + 10.719 0.999973 1749664 36408.89 + 10.759 0.999976 1749668 40960.00 + 10.823 0.999979 1749673 46811.43 + 10.847 0.999982 1749679 54613.33 + 10.943 0.999985 1749684 65536.00 + 11.007 0.999986 1749687 72817.78 + 11.055 0.999988 1749689 81920.00 + 11.071 0.999989 1749692 93622.86 + 11.223 0.999991 1749694 109226.67 + 11.375 0.999992 1749697 131072.00 + 11.383 0.999993 1749698 145635.56 + 11.415 0.999994 1749700 163840.00 + 11.439 0.999995 1749701 187245.71 + 11.511 0.999995 1749703 218453.33 + 11.663 0.999996 1749704 262144.00 + 11.663 0.999997 1749704 291271.11 + 11.735 0.999997 1749705 327680.00 + 11.767 0.999997 1749707 374491.43 + 11.767 0.999998 1749707 436906.67 + 11.767 0.999998 1749707 524288.00 + 11.767 0.999998 1749707 582542.22 + 12.079 0.999998 1749708 655360.00 + 12.079 0.999999 1749708 748982.86 + 12.079 0.999999 1749708 873813.33 + 12.367 0.999999 1749709 1048576.00 + 12.367 0.999999 1749709 1165084.44 + 12.367 0.999999 1749709 1310720.00 + 12.367 0.999999 1749709 1497965.71 + 12.367 0.999999 1749709 1747626.67 + 12.447 1.000000 1749710 2097152.00 + 12.447 1.000000 1749710 inf +#[Mean = 4.147, StdDeviation = 1.361] +#[Max = 12.440, Total count = 1749710] +#[Buckets = 27, SubBuckets = 2048] +---------------------------------------------------------- + 1903943 requests in 2.00m, 135.11MB read +Requests/sec: 15865.83 +Transfer/sec: 1.13MB + +---------------------------------------------------------------------------------------------- From d51771f9846c49ee062bee7f027a44051eae89a6 Mon Sep 17 00:00:00 2001 From: sbread Date: Thu, 14 Mar 2024 15:35:27 +0300 Subject: [PATCH 12/23] code --- .../vk/itmo/test/osipovdaniil/ServerImpl.java | 79 +++++++++++++++---- .../test/osipovdaniil/ServiceFactoryImpl.java | 2 +- .../itmo/test/osipovdaniil/ServiceImpl.java | 9 ++- 3 files changed, 73 insertions(+), 17 deletions(-) diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java index a0e132dfb..c67a5d716 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java @@ -1,24 +1,22 @@ package ru.vk.itmo.test.osipovdaniil; -import one.nio.http.HttpServer; -import one.nio.http.HttpServerConfig; -import one.nio.http.HttpSession; -import one.nio.http.Param; -import one.nio.http.Path; -import one.nio.http.Request; -import one.nio.http.RequestMethod; -import one.nio.http.Response; +import one.nio.http.*; import one.nio.server.AcceptorConfig; +import one.nio.util.Hash; import ru.vk.itmo.ServiceConfig; import ru.vk.itmo.dao.BaseEntry; import ru.vk.itmo.dao.Entry; import ru.vk.itmo.test.osipovdaniil.dao.ReferenceDao; - import java.io.IOException; -import java.io.UncheckedIOException; import java.lang.foreign.MemorySegment; import java.lang.foreign.ValueLayout; +import java.net.HttpURLConnection; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; import java.nio.charset.StandardCharsets; +import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.RejectedExecutionException; @@ -32,15 +30,21 @@ public class ServerImpl extends HttpServer { private static final Integer MAX_THREADS = 64; private static final String ID = "id="; private final ExecutorService requestExecutor; + private final List clusterUrls; private final Logger logger; private final ReferenceDao dao; + private final String url; + private final HttpClient httpClient; public ServerImpl(final ServiceConfig serviceConfig, ReferenceDao dao) throws IOException { super(createHttpServerConfig(serviceConfig)); this.dao = dao; this.requestExecutor = Executors.newFixedThreadPool(MAX_THREADS); this.logger = Logger.getLogger(ServerImpl.class.getName()); + this.clusterUrls = serviceConfig.clusterUrls(); + this.url = serviceConfig.selfUrl(); + this.httpClient = HttpClient.newHttpClient(); } private static HttpServerConfig createHttpServerConfig(final ServiceConfig serviceConfig) { @@ -65,6 +69,42 @@ private Response requestHandle(final String id, final Function response = processProxyRequest(request, url); + final String statusCode = switch (response.statusCode()) { + case HttpURLConnection.HTTP_OK -> Response.OK; + case HttpURLConnection.HTTP_CREATED -> Response.CREATED; + case HttpURLConnection.HTTP_ACCEPTED -> Response.ACCEPTED; + case HttpURLConnection.HTTP_BAD_REQUEST -> Response.BAD_REQUEST; + case HttpURLConnection.HTTP_NOT_FOUND -> Response.NOT_FOUND; + default -> throw new IllegalStateException("Unexpected response status code: " + response.statusCode()); + }; + return new Response(statusCode, response.body()); + } + + private HttpResponse processProxyRequest(final Request request, final String url) throws IOException, + InterruptedException { + final byte[] rBody = request.getBody(); + final byte[] requestBody = rBody == null ? new byte[0] : rBody; + return httpClient + .send(HttpRequest.newBuilder(URI.create(url + request.getURI())) + .method(request.getMethodName(), HttpRequest.BodyPublishers.ofByteArray(requestBody)) + .build(), HttpResponse.BodyHandlers.ofByteArray()); + } + + private String getTargetUrl(final String id) { + int max = 0; + int maxId = 0; + for (int i = 0; i < clusterUrls.size(); i++) { + int hash = Hash.murmur3(id + i); + if (hash > max) { + max = hash; + maxId = i; + } + } + return clusterUrls.get(maxId); + } + @Path(ENTITY_PATH) @RequestMethod(Request.METHOD_GET) public Response get(@Param("id") final String id) { @@ -105,6 +145,11 @@ private void handleRequestTask(final Request request, final HttpSession session) session.sendResponse(response); return; } + final String targetUrl = getTargetUrl(request.getParameter(ID)); + if (!url.equals(targetUrl)) { + session.sendResponse(handleProxyRequest(request, targetUrl)); + return; + } final int method = request.getMethod(); if (method == Request.METHOD_GET) { response = get(request.getParameter(ID)); @@ -116,9 +161,14 @@ private void handleRequestTask(final Request request, final HttpSession session) response = new Response(Response.METHOD_NOT_ALLOWED, Response.EMPTY); } session.sendResponse(response); - } catch (IOException e) { - logger.info("IO exception in execution request: " + request + "\n"); - throw new UncheckedIOException(e); + } catch (IOException | InterruptedException e) { + try { + session.sendResponse(new Response(Response.INTERNAL_ERROR, Response.EMPTY)); + } catch (IOException e1) { + logger.info(e.getMessage()); + } + logger.info("IO or Interrupted exception in execution request: " + request + "\n"); + Thread.currentThread().interrupt(); } } @@ -148,7 +198,8 @@ void shutdownAndAwaitTermination(ExecutorService pool) { @Override public synchronized void stop() { - shutdownAndAwaitTermination(requestExecutor); super.stop(); + shutdownAndAwaitTermination(requestExecutor); + httpClient.close(); } } diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/ServiceFactoryImpl.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/ServiceFactoryImpl.java index 2eed10d26..5b181552e 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/ServiceFactoryImpl.java +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/ServiceFactoryImpl.java @@ -4,7 +4,7 @@ import ru.vk.itmo.ServiceConfig; import ru.vk.itmo.test.ServiceFactory; -@ServiceFactory(stage = 2) +@ServiceFactory(stage = 3) public class ServiceFactoryImpl implements ServiceFactory.Factory { @Override diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/ServiceImpl.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/ServiceImpl.java index 72dab167c..e9f1cc3ab 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/ServiceImpl.java +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/ServiceImpl.java @@ -6,6 +6,7 @@ import ru.vk.itmo.test.osipovdaniil.dao.ReferenceDao; import java.io.IOException; +import java.io.UncheckedIOException; import java.util.concurrent.CompletableFuture; public class ServiceImpl implements Service { @@ -35,9 +36,13 @@ public CompletableFuture start() throws IOException { } @Override - public CompletableFuture stop() throws IOException { + public CompletableFuture stop() { server.stop(); - dao.close(); + try { + dao.close(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } return CompletableFuture.completedFuture(null); } } From 0cd0e1632e4692c91ec170308273932204787a6d Mon Sep 17 00:00:00 2001 From: sbread Date: Thu, 14 Mar 2024 15:42:13 +0300 Subject: [PATCH 13/23] code climate --- .../ru/vk/itmo/test/osipovdaniil/ServerImpl.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java index c67a5d716..6fa827130 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java @@ -1,6 +1,14 @@ package ru.vk.itmo.test.osipovdaniil; -import one.nio.http.*; + +import one.nio.http.HttpServer; +import one.nio.http.HttpServerConfig; +import one.nio.http.HttpSession; +import one.nio.http.Param; +import one.nio.http.Path; +import one.nio.http.Request; +import one.nio.http.RequestMethod; +import one.nio.http.Response; import one.nio.server.AcceptorConfig; import one.nio.util.Hash; import ru.vk.itmo.ServiceConfig; @@ -69,7 +77,8 @@ private Response requestHandle(final String id, final Function response = processProxyRequest(request, url); final String statusCode = switch (response.statusCode()) { case HttpURLConnection.HTTP_OK -> Response.OK; From 2bca7154f6454c1b3065b6cfaf7333ccff1f9fad Mon Sep 17 00:00:00 2001 From: sbread Date: Thu, 14 Mar 2024 15:45:09 +0300 Subject: [PATCH 14/23] code climate 2 --- src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java index 6fa827130..050010a46 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java @@ -1,6 +1,5 @@ package ru.vk.itmo.test.osipovdaniil; - import one.nio.http.HttpServer; import one.nio.http.HttpServerConfig; import one.nio.http.HttpSession; From 4cd83a01b89d9e0ac73819fa768443105b7689f3 Mon Sep 17 00:00:00 2001 From: sbread Date: Wed, 20 Mar 2024 22:50:44 +0300 Subject: [PATCH 15/23] report3 --- .../report3/asyncprof/prof_get_alloc_128.html | 457 ++++ .../report3/asyncprof/prof_get_alloc_64.html | 467 ++++ .../report3/asyncprof/prof_get_cpu_128.html | 2116 +++++++++++++++ .../report3/asyncprof/prof_get_cpu_64.html | 1914 ++++++++++++++ .../report3/asyncprof/prof_get_lock_128.html | 336 +++ .../report3/asyncprof/prof_get_lock_64.html | 336 +++ .../report3/asyncprof/prof_put_alloc_128.html | 495 ++++ .../report3/asyncprof/prof_put_alloc_64.html | 507 ++++ .../report3/asyncprof/prof_put_cpu_128.html | 2304 +++++++++++++++++ .../report3/asyncprof/prof_put_cpu_64.html | 2067 +++++++++++++++ .../report3/asyncprof/prof_put_lock_128.html | 385 +++ .../report3/asyncprof/prof_put_lock_64.html | 371 +++ .../itmo/test/osipovdaniil/report3/report3.md | 21 + .../test/osipovdaniil/report3/wrk/wrk_res | 492 ++++ 14 files changed, 12268 insertions(+) create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/report3/asyncprof/prof_get_alloc_128.html create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/report3/asyncprof/prof_get_alloc_64.html create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/report3/asyncprof/prof_get_cpu_128.html create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/report3/asyncprof/prof_get_cpu_64.html create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/report3/asyncprof/prof_get_lock_128.html create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/report3/asyncprof/prof_get_lock_64.html create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/report3/asyncprof/prof_put_alloc_128.html create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/report3/asyncprof/prof_put_alloc_64.html create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/report3/asyncprof/prof_put_cpu_128.html create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/report3/asyncprof/prof_put_cpu_64.html create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/report3/asyncprof/prof_put_lock_128.html create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/report3/asyncprof/prof_put_lock_64.html create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/report3/report3.md create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/report3/wrk/wrk_res diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/report3/asyncprof/prof_get_alloc_128.html b/src/main/java/ru/vk/itmo/test/osipovdaniil/report3/asyncprof/prof_get_alloc_128.html new file mode 100644 index 000000000..885750998 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/report3/asyncprof/prof_get_alloc_128.html @@ -0,0 +1,457 @@ + + + + + + + +

Allocation profile

+
  
+
Produced by async-profiler
+ +
+

+

Matched:

+ diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/report3/asyncprof/prof_get_alloc_64.html b/src/main/java/ru/vk/itmo/test/osipovdaniil/report3/asyncprof/prof_get_alloc_64.html new file mode 100644 index 000000000..aacfbb986 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/report3/asyncprof/prof_get_alloc_64.html @@ -0,0 +1,467 @@ + + + + + + + +

Allocation profile

+
  
+
Produced by async-profiler
+ +
+

+

Matched:

+ diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/report3/asyncprof/prof_get_cpu_128.html b/src/main/java/ru/vk/itmo/test/osipovdaniil/report3/asyncprof/prof_get_cpu_128.html new file mode 100644 index 000000000..376f8c336 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/report3/asyncprof/prof_get_cpu_128.html @@ -0,0 +1,2116 @@ + + + + + + + +

CPU profile

+
  
+
Produced by async-profiler
+ +
+

+

Matched:

+ diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/report3/asyncprof/prof_get_cpu_64.html b/src/main/java/ru/vk/itmo/test/osipovdaniil/report3/asyncprof/prof_get_cpu_64.html new file mode 100644 index 000000000..430eee540 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/report3/asyncprof/prof_get_cpu_64.html @@ -0,0 +1,1914 @@ + + + + + + + +

CPU profile

+
  
+
Produced by async-profiler
+ +
+

+

Matched:

+ diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/report3/asyncprof/prof_get_lock_128.html b/src/main/java/ru/vk/itmo/test/osipovdaniil/report3/asyncprof/prof_get_lock_128.html new file mode 100644 index 000000000..5ce4fbc4f --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/report3/asyncprof/prof_get_lock_128.html @@ -0,0 +1,336 @@ + + + + + + + +

Lock profile

+
  
+
Produced by async-profiler
+ +
+

+

Matched:

+ diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/report3/asyncprof/prof_get_lock_64.html b/src/main/java/ru/vk/itmo/test/osipovdaniil/report3/asyncprof/prof_get_lock_64.html new file mode 100644 index 000000000..e0815cef2 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/report3/asyncprof/prof_get_lock_64.html @@ -0,0 +1,336 @@ + + + + + + + +

Lock profile

+
  
+
Produced by async-profiler
+ +
+

+

Matched:

+ diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/report3/asyncprof/prof_put_alloc_128.html b/src/main/java/ru/vk/itmo/test/osipovdaniil/report3/asyncprof/prof_put_alloc_128.html new file mode 100644 index 000000000..4f4ada0f3 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/report3/asyncprof/prof_put_alloc_128.html @@ -0,0 +1,495 @@ + + + + + + + +

Allocation profile

+
  
+
Produced by async-profiler
+ +
+

+

Matched:

+ diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/report3/asyncprof/prof_put_alloc_64.html b/src/main/java/ru/vk/itmo/test/osipovdaniil/report3/asyncprof/prof_put_alloc_64.html new file mode 100644 index 000000000..731c17fad --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/report3/asyncprof/prof_put_alloc_64.html @@ -0,0 +1,507 @@ + + + + + + + +

Allocation profile

+
  
+
Produced by async-profiler
+ +
+

+

Matched:

+ diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/report3/asyncprof/prof_put_cpu_128.html b/src/main/java/ru/vk/itmo/test/osipovdaniil/report3/asyncprof/prof_put_cpu_128.html new file mode 100644 index 000000000..8455381f6 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/report3/asyncprof/prof_put_cpu_128.html @@ -0,0 +1,2304 @@ + + + + + + + +

CPU profile

+
  
+
Produced by async-profiler
+ +
+

+

Matched:

+ diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/report3/asyncprof/prof_put_cpu_64.html b/src/main/java/ru/vk/itmo/test/osipovdaniil/report3/asyncprof/prof_put_cpu_64.html new file mode 100644 index 000000000..753cf9e96 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/report3/asyncprof/prof_put_cpu_64.html @@ -0,0 +1,2067 @@ + + + + + + + +

CPU profile

+
  
+
Produced by async-profiler
+ +
+

+

Matched:

+ diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/report3/asyncprof/prof_put_lock_128.html b/src/main/java/ru/vk/itmo/test/osipovdaniil/report3/asyncprof/prof_put_lock_128.html new file mode 100644 index 000000000..0c7f224c2 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/report3/asyncprof/prof_put_lock_128.html @@ -0,0 +1,385 @@ + + + + + + + +

Lock profile

+
  
+
Produced by async-profiler
+ +
+

+

Matched:

+ diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/report3/asyncprof/prof_put_lock_64.html b/src/main/java/ru/vk/itmo/test/osipovdaniil/report3/asyncprof/prof_put_lock_64.html new file mode 100644 index 000000000..eb8136021 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/report3/asyncprof/prof_put_lock_64.html @@ -0,0 +1,371 @@ + + + + + + + +

Lock profile

+
  
+
Produced by async-profiler
+ +
+

+

Matched:

+ diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/report3/report3.md b/src/main/java/ru/vk/itmo/test/osipovdaniil/report3/report3.md new file mode 100644 index 000000000..ab2e2bc14 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/report3/report3.md @@ -0,0 +1,21 @@ +# Отчёт по 3 стэйджу + +## wrk + +Минорная разница по сравнению со 2 стейджем в небоьшом увеличении времени ответа +в связи с выбором кластера. + +## asyncprof + +С точки зрения cpu разницы нет. +Например: [cpu1](../report2/asyncprof/prof_128_cpu_put.html) +и [cpu2](asyncprof/prof_get_cpu_128.html) + +С точки зрения аллокаций добавляется аллокации на `handleProxyRequest` +отвечающий за обработку запроса другим кластером, а также на `getTargetUrl` +[alloc](asyncprof/prof_get_alloc_128.html) + +В случае с lock'ами, тзменилось только их распределение, так `SelectorThread` стал отжирать больше, а lock на саму +таску меньше. +[lock1](../report2/asyncprof/prof_128_lock_put.html) +и [lock2](asyncprof/prof_get_lock_128.html) diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/report3/wrk/wrk_res b/src/main/java/ru/vk/itmo/test/osipovdaniil/report3/wrk/wrk_res new file mode 100644 index 000000000..9c0bb7c99 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/report3/wrk/wrk_res @@ -0,0 +1,492 @@ +./wrk -d 30 -t 1 -c 64 -R 18500 -L -s /home/sbread/Desktop/labs/HLS/2024-highload-dht/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/put.lua http://localhost:8080 +Running 30s test @ http://localhost:8080 + 1 threads and 64 connections + Thread calibration: mean lat.: 2.073ms, rate sampling interval: 10ms + Thread Stats Avg Stdev Max +/- Stdev + Latency 2.10ms 0.95ms 11.75ms 68.69% + Req/Sec 19.48k 2.16k 30.67k 69.06% + Latency Distribution (HdrHistogram - Recorded Latency) + 50.000% 2.00ms + 75.000% 2.62ms + 90.000% 3.38ms + 99.000% 4.70ms + 99.900% 6.18ms + 99.990% 8.82ms + 99.999% 10.94ms +100.000% 11.76ms + + Detailed Percentile spectrum: + Value Percentile TotalCount 1/(1-Percentile) + + 0.110 0.000000 1 1.00 + 0.961 0.100000 36453 1.11 + 1.274 0.200000 72897 1.25 + 1.550 0.300000 109307 1.43 + 1.778 0.400000 145678 1.67 + 1.995 0.500000 182082 2.00 + 2.107 0.550000 200296 2.22 + 2.221 0.600000 218572 2.50 + 2.339 0.650000 236807 2.86 + 2.469 0.700000 254900 3.33 + 2.625 0.750000 273066 4.00 + 2.715 0.775000 282216 4.44 + 2.817 0.800000 291339 5.00 + 2.935 0.825000 300416 5.71 + 3.069 0.850000 309564 6.67 + 3.217 0.875000 318569 8.00 + 3.299 0.887500 323182 8.89 + 3.385 0.900000 327745 10.00 + 3.477 0.912500 332241 11.43 + 3.589 0.925000 336811 13.33 + 3.731 0.937500 341344 16.00 + 3.815 0.943750 343636 17.78 + 3.905 0.950000 345875 20.00 + 4.001 0.956250 348179 22.86 + 4.099 0.962500 350440 26.67 + 4.203 0.968750 352792 32.00 + 4.251 0.971875 353881 35.56 + 4.303 0.975000 355013 40.00 + 4.359 0.978125 356181 45.71 + 4.419 0.981250 357284 53.33 + 4.495 0.984375 358429 64.00 + 4.535 0.985938 358961 71.11 + 4.587 0.987500 359546 80.00 + 4.651 0.989062 360118 91.43 + 4.723 0.990625 360688 106.67 + 4.799 0.992188 361266 128.00 + 4.843 0.992969 361531 142.22 + 4.887 0.993750 361807 160.00 + 4.939 0.994531 362091 182.86 + 4.999 0.995313 362387 213.33 + 5.067 0.996094 362660 256.00 + 5.111 0.996484 362809 284.44 + 5.155 0.996875 362940 320.00 + 5.227 0.997266 363082 365.71 + 5.339 0.997656 363224 426.67 + 5.511 0.998047 363365 512.00 + 5.611 0.998242 363439 568.89 + 5.715 0.998437 363508 640.00 + 5.827 0.998633 363579 731.43 + 5.987 0.998828 363650 853.33 + 6.203 0.999023 363721 1024.00 + 6.347 0.999121 363757 1137.78 + 6.515 0.999219 363793 1280.00 + 6.723 0.999316 363828 1462.86 + 6.927 0.999414 363863 1706.67 + 7.139 0.999512 363899 2048.00 + 7.307 0.999561 363917 2275.56 + 7.435 0.999609 363934 2560.00 + 7.695 0.999658 363952 2925.71 + 7.879 0.999707 363970 3413.33 + 8.099 0.999756 363988 4096.00 + 8.171 0.999780 363998 4551.11 + 8.255 0.999805 364005 5120.00 + 8.375 0.999829 364015 5851.43 + 8.503 0.999854 364024 6826.67 + 8.639 0.999878 364033 8192.00 + 8.767 0.999890 364037 9102.22 + 8.847 0.999902 364041 10240.00 + 8.911 0.999915 364046 11702.86 + 9.031 0.999927 364051 13653.33 + 9.135 0.999939 364055 16384.00 + 9.215 0.999945 364057 18204.44 + 9.287 0.999951 364059 20480.00 + 9.391 0.999957 364061 23405.71 + 9.711 0.999963 364063 27306.67 + 9.751 0.999969 364065 32768.00 + 9.871 0.999973 364067 36408.89 + 10.039 0.999976 364068 40960.00 + 10.055 0.999979 364069 46811.43 + 10.719 0.999982 364070 54613.33 + 10.927 0.999985 364071 65536.00 + 10.935 0.999986 364072 72817.78 + 10.935 0.999988 364072 81920.00 + 11.167 0.999989 364073 93622.86 + 11.167 0.999991 364073 109226.67 + 11.215 0.999992 364074 131072.00 + 11.215 0.999993 364074 145635.56 + 11.215 0.999994 364074 163840.00 + 11.631 0.999995 364075 187245.71 + 11.631 0.999995 364075 218453.33 + 11.631 0.999996 364075 262144.00 + 11.631 0.999997 364075 291271.11 + 11.631 0.999997 364075 327680.00 + 11.759 0.999997 364076 374491.43 + 11.759 1.000000 364076 inf +#[Mean = 2.101, StdDeviation = 0.947] +#[Max = 11.752, Total count = 364076] +#[Buckets = 27, SubBuckets = 2048] +---------------------------------------------------------- + 552109 requests in 30.00s, 35.28MB read +Requests/sec: 18402.34 +Transfer/sec: 1.18MB + +----------------------------------------------------------------------------------------- + +./wrk -d 30 -t 1 -c 128 -R 18500 -L -s /home/sbread/Desktop/labs/HLS/2024-highload-dht/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/put.lua http://localhost:8080 +Running 30s test @ http://localhost:8080 + 1 threads and 128 connections + Thread calibration: mean lat.: 3.992ms, rate sampling interval: 12ms + Thread Stats Avg Stdev Max +/- Stdev + Latency 3.96ms 1.72ms 13.05ms 66.23% + Req/Sec 19.37k 3.90k 32.36k 70.13% + Latency Distribution (HdrHistogram - Recorded Latency) + 50.000% 3.79ms + 75.000% 5.11ms + 90.000% 6.40ms + 99.000% 8.24ms + 99.900% 9.20ms + 99.990% 10.75ms + 99.999% 12.47ms +100.000% 13.06ms + + Detailed Percentile spectrum: + Value Percentile TotalCount 1/(1-Percentile) + + 0.295 0.000000 1 1.00 + 1.800 0.100000 35820 1.11 + 2.413 0.200000 71702 1.25 + 2.909 0.300000 107508 1.43 + 3.359 0.400000 143352 1.67 + 3.789 0.500000 179119 2.00 + 4.011 0.550000 197053 2.22 + 4.247 0.600000 215082 2.50 + 4.503 0.650000 233082 2.86 + 4.791 0.700000 250837 3.33 + 5.107 0.750000 268739 4.00 + 5.275 0.775000 277775 4.44 + 5.447 0.800000 286647 5.00 + 5.639 0.825000 295673 5.71 + 5.855 0.850000 304585 6.67 + 6.111 0.875000 313401 8.00 + 6.255 0.887500 317951 8.89 + 6.403 0.900000 322403 10.00 + 6.555 0.912500 326875 11.43 + 6.719 0.925000 331389 13.33 + 6.899 0.937500 335788 16.00 + 7.003 0.943750 338061 17.78 + 7.115 0.950000 340314 20.00 + 7.235 0.956250 342534 22.86 + 7.371 0.962500 344781 26.67 + 7.519 0.968750 347030 32.00 + 7.595 0.971875 348136 35.56 + 7.675 0.975000 349252 40.00 + 7.763 0.978125 350371 45.71 + 7.863 0.981250 351482 53.33 + 7.975 0.984375 352582 64.00 + 8.039 0.985938 353140 71.11 + 8.107 0.987500 353697 80.00 + 8.183 0.989062 354269 91.43 + 8.271 0.990625 354849 106.67 + 8.367 0.992188 355419 128.00 + 8.415 0.992969 355696 142.22 + 8.471 0.993750 355968 160.00 + 8.527 0.994531 356239 182.86 + 8.583 0.995313 356495 213.33 + 8.655 0.996094 356779 256.00 + 8.695 0.996484 356920 284.44 + 8.743 0.996875 357067 320.00 + 8.791 0.997266 357205 365.71 + 8.847 0.997656 357333 426.67 + 8.919 0.998047 357482 512.00 + 8.959 0.998242 357549 568.89 + 9.007 0.998437 357616 640.00 + 9.071 0.998633 357688 731.43 + 9.143 0.998828 357761 853.33 + 9.223 0.999023 357834 1024.00 + 9.255 0.999121 357862 1137.78 + 9.303 0.999219 357894 1280.00 + 9.351 0.999316 357929 1462.86 + 9.415 0.999414 357966 1706.67 + 9.479 0.999512 357999 2048.00 + 9.527 0.999561 358016 2275.56 + 9.591 0.999609 358035 2560.00 + 9.671 0.999658 358050 2925.71 + 9.815 0.999707 358068 3413.33 + 9.943 0.999756 358085 4096.00 + 10.063 0.999780 358094 4551.11 + 10.151 0.999805 358103 5120.00 + 10.231 0.999829 358111 5851.43 + 10.367 0.999854 358120 6826.67 + 10.535 0.999878 358129 8192.00 + 10.639 0.999890 358133 9102.22 + 10.791 0.999902 358138 10240.00 + 10.967 0.999915 358142 11702.86 + 11.039 0.999927 358147 13653.33 + 11.143 0.999939 358151 16384.00 + 11.207 0.999945 358153 18204.44 + 11.319 0.999951 358156 20480.00 + 11.343 0.999957 358157 23405.71 + 11.511 0.999963 358159 27306.67 + 11.943 0.999969 358162 32768.00 + 12.015 0.999973 358163 36408.89 + 12.055 0.999976 358164 40960.00 + 12.063 0.999979 358165 46811.43 + 12.135 0.999982 358166 54613.33 + 12.383 0.999985 358167 65536.00 + 12.471 0.999986 358168 72817.78 + 12.471 0.999988 358168 81920.00 + 12.591 0.999989 358169 93622.86 + 12.591 0.999991 358169 109226.67 + 12.703 0.999992 358170 131072.00 + 12.703 0.999993 358170 145635.56 + 12.703 0.999994 358170 163840.00 + 12.935 0.999995 358171 187245.71 + 12.935 0.999995 358171 218453.33 + 12.935 0.999996 358171 262144.00 + 12.935 0.999997 358171 291271.11 + 12.935 0.999997 358171 327680.00 + 13.055 0.999997 358172 374491.43 + 13.055 1.000000 358172 inf +#[Mean = 3.964, StdDeviation = 1.722] +#[Max = 13.048, Total count = 358172] +#[Buckets = 27, SubBuckets = 2048] +---------------------------------------------------------- + 536397 requests in 30.00s, 34.27MB read +Requests/sec: 17878.56 +Transfer/sec: 1.14MB + +-------------------------------------------------------------------------------- + +./wrk -d 30 -t 1 -c 128 -R 18500 -L -s /home/sbread/Desktop/labs/HLS/2024-highload-dht/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/get.lua http://localhost:8080 +Running 30s test @ http://localhost:8080 + 1 threads and 128 connections + Thread calibration: mean lat.: 3.840ms, rate sampling interval: 11ms + Thread Stats Avg Stdev Max +/- Stdev + Latency 3.86ms 1.62ms 11.00ms 66.85% + Req/Sec 19.45k 3.62k 31.09k 66.71% + Latency Distribution (HdrHistogram - Recorded Latency) + 50.000% 3.72ms + 75.000% 4.93ms + 90.000% 6.04ms + 99.000% 8.06ms + 99.900% 9.02ms + 99.990% 9.63ms + 99.999% 10.47ms +100.000% 11.01ms + + Detailed Percentile spectrum: + Value Percentile TotalCount 1/(1-Percentile) + + 0.242 0.000000 1 1.00 + 1.792 0.100000 35821 1.11 + 2.417 0.200000 71680 1.25 + 2.885 0.300000 107444 1.43 + 3.305 0.400000 143356 1.67 + 3.725 0.500000 179208 2.00 + 3.931 0.550000 197126 2.22 + 4.139 0.600000 214943 2.50 + 4.371 0.650000 233018 2.86 + 4.631 0.700000 250740 3.33 + 4.927 0.750000 268782 4.00 + 5.079 0.775000 277643 4.44 + 5.239 0.800000 286739 5.00 + 5.399 0.825000 295563 5.71 + 5.567 0.850000 304432 6.67 + 5.775 0.875000 313535 8.00 + 5.899 0.887500 317870 8.89 + 6.043 0.900000 322355 10.00 + 6.203 0.912500 326916 11.43 + 6.371 0.925000 331335 13.33 + 6.559 0.937500 335826 16.00 + 6.667 0.943750 338091 17.78 + 6.775 0.950000 340245 20.00 + 6.903 0.956250 342527 22.86 + 7.039 0.962500 344738 26.67 + 7.203 0.968750 346982 32.00 + 7.291 0.971875 348076 35.56 + 7.391 0.975000 349228 40.00 + 7.491 0.978125 350321 45.71 + 7.611 0.981250 351444 53.33 + 7.743 0.984375 352563 64.00 + 7.815 0.985938 353120 71.11 + 7.911 0.987500 353682 80.00 + 8.003 0.989062 354253 91.43 + 8.103 0.990625 354800 106.67 + 8.207 0.992188 355352 128.00 + 8.271 0.992969 355651 142.22 + 8.335 0.993750 355913 160.00 + 8.407 0.994531 356210 182.86 + 8.471 0.995313 356480 213.33 + 8.551 0.996094 356767 256.00 + 8.583 0.996484 356889 284.44 + 8.631 0.996875 357035 320.00 + 8.679 0.997266 357184 365.71 + 8.735 0.997656 357318 426.67 + 8.799 0.998047 357453 512.00 + 8.831 0.998242 357518 568.89 + 8.871 0.998437 357587 640.00 + 8.919 0.998633 357673 731.43 + 8.959 0.998828 357728 853.33 + 9.023 0.999023 357801 1024.00 + 9.047 0.999121 357835 1137.78 + 9.071 0.999219 357865 1280.00 + 9.111 0.999316 357904 1462.86 + 9.159 0.999414 357937 1706.67 + 9.231 0.999512 357972 2048.00 + 9.279 0.999561 357989 2275.56 + 9.327 0.999609 358008 2560.00 + 9.383 0.999658 358028 2925.71 + 9.415 0.999707 358042 3413.33 + 9.455 0.999756 358060 4096.00 + 9.471 0.999780 358066 4551.11 + 9.495 0.999805 358075 5120.00 + 9.511 0.999829 358085 5851.43 + 9.535 0.999854 358093 6826.67 + 9.575 0.999878 358101 8192.00 + 9.607 0.999890 358106 9102.22 + 9.639 0.999902 358110 10240.00 + 9.719 0.999915 358115 11702.86 + 9.767 0.999927 358118 13653.33 + 9.799 0.999939 358123 16384.00 + 9.823 0.999945 358125 18204.44 + 9.855 0.999951 358127 20480.00 + 9.927 0.999957 358129 23405.71 + 9.991 0.999963 358131 27306.67 + 10.071 0.999969 358134 32768.00 + 10.143 0.999973 358136 36408.89 + 10.143 0.999976 358136 40960.00 + 10.159 0.999979 358137 46811.43 + 10.199 0.999982 358138 54613.33 + 10.423 0.999985 358139 65536.00 + 10.471 0.999986 358140 72817.78 + 10.471 0.999988 358140 81920.00 + 10.479 0.999989 358141 93622.86 + 10.479 0.999991 358141 109226.67 + 10.511 0.999992 358142 131072.00 + 10.511 0.999993 358142 145635.56 + 10.511 0.999994 358142 163840.00 + 10.543 0.999995 358143 187245.71 + 10.543 0.999995 358143 218453.33 + 10.543 0.999996 358143 262144.00 + 10.543 0.999997 358143 291271.11 + 10.543 0.999997 358143 327680.00 + 11.007 0.999997 358144 374491.43 + 11.007 1.000000 358144 inf +#[Mean = 3.855, StdDeviation = 1.617] +#[Max = 11.000, Total count = 358144] +#[Buckets = 27, SubBuckets = 2048] +---------------------------------------------------------- + 549150 requests in 30.00s, 38.64MB read +Requests/sec: 18303.87 +Transfer/sec: 1.29MB + +--------------------------------------------------------------------------- + +./wrk -d 30 -t 1 -c 64 -R 18500 -L -s /home/sbread/Desktop/labs/HLS/2024-highload-dht/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/get.lua http://localhost:8080 +Running 30s test @ http://localhost:8080 + 1 threads and 64 connections + Thread calibration: mean lat.: 2.050ms, rate sampling interval: 10ms + Thread Stats Avg Stdev Max +/- Stdev + Latency 2.08ms 0.91ms 7.37ms 68.17% + Req/Sec 19.52k 2.19k 27.00k 66.20% + Latency Distribution (HdrHistogram - Recorded Latency) + 50.000% 1.98ms + 75.000% 2.60ms + 90.000% 3.34ms + 99.000% 4.59ms + 99.900% 5.29ms + 99.990% 5.78ms + 99.999% 7.14ms +100.000% 7.38ms + + Detailed Percentile spectrum: + Value Percentile TotalCount 1/(1-Percentile) + + 0.118 0.000000 1 1.00 + 0.965 0.100000 36409 1.11 + 1.270 0.200000 72816 1.25 + 1.536 0.300000 109367 1.43 + 1.762 0.400000 145691 1.67 + 1.977 0.500000 182176 2.00 + 2.089 0.550000 200248 2.22 + 2.203 0.600000 218670 2.50 + 2.321 0.650000 236899 2.86 + 2.451 0.700000 254998 3.33 + 2.601 0.750000 273252 4.00 + 2.685 0.775000 282215 4.44 + 2.783 0.800000 291319 5.00 + 2.895 0.825000 300378 5.71 + 3.025 0.850000 309493 6.67 + 3.177 0.875000 318642 8.00 + 3.257 0.887500 323158 8.89 + 3.337 0.900000 327704 10.00 + 3.423 0.912500 332285 11.43 + 3.525 0.925000 336778 13.33 + 3.655 0.937500 341371 16.00 + 3.731 0.943750 343611 17.78 + 3.819 0.950000 345906 20.00 + 3.913 0.956250 348155 22.86 + 4.015 0.962500 350419 26.67 + 4.123 0.968750 352730 32.00 + 4.175 0.971875 353884 35.56 + 4.227 0.975000 354973 40.00 + 4.283 0.978125 356148 45.71 + 4.343 0.981250 357279 53.33 + 4.411 0.984375 358376 64.00 + 4.455 0.985938 358999 71.11 + 4.499 0.987500 359538 80.00 + 4.551 0.989062 360102 91.43 + 4.611 0.990625 360678 106.67 + 4.679 0.992188 361231 128.00 + 4.719 0.992969 361525 142.22 + 4.755 0.993750 361798 160.00 + 4.795 0.994531 362080 182.86 + 4.839 0.995313 362358 213.33 + 4.895 0.996094 362656 256.00 + 4.919 0.996484 362791 284.44 + 4.951 0.996875 362936 320.00 + 4.983 0.997266 363089 365.71 + 5.019 0.997656 363219 426.67 + 5.071 0.998047 363363 512.00 + 5.099 0.998242 363430 568.89 + 5.131 0.998437 363499 640.00 + 5.167 0.998633 363567 731.43 + 5.231 0.998828 363638 853.33 + 5.295 0.999023 363715 1024.00 + 5.331 0.999121 363745 1137.78 + 5.367 0.999219 363780 1280.00 + 5.415 0.999316 363821 1462.86 + 5.443 0.999414 363851 1706.67 + 5.503 0.999512 363888 2048.00 + 5.519 0.999561 363906 2275.56 + 5.547 0.999609 363925 2560.00 + 5.571 0.999658 363942 2925.71 + 5.603 0.999707 363958 3413.33 + 5.631 0.999756 363977 4096.00 + 5.647 0.999780 363986 4551.11 + 5.675 0.999805 363998 5120.00 + 5.687 0.999829 364003 5851.43 + 5.711 0.999854 364011 6826.67 + 5.743 0.999878 364020 8192.00 + 5.767 0.999890 364025 9102.22 + 5.787 0.999902 364030 10240.00 + 5.807 0.999915 364033 11702.86 + 5.863 0.999927 364038 13653.33 + 5.879 0.999939 364042 16384.00 + 5.919 0.999945 364045 18204.44 + 5.935 0.999951 364047 20480.00 + 5.971 0.999957 364049 23405.71 + 5.991 0.999963 364051 27306.67 + 6.067 0.999969 364053 32768.00 + 6.503 0.999973 364055 36408.89 + 6.587 0.999976 364056 40960.00 + 6.895 0.999979 364057 46811.43 + 7.091 0.999982 364058 54613.33 + 7.135 0.999985 364059 65536.00 + 7.139 0.999986 364060 72817.78 + 7.139 0.999988 364060 81920.00 + 7.163 0.999989 364061 93622.86 + 7.163 0.999991 364061 109226.67 + 7.283 0.999992 364062 131072.00 + 7.283 0.999993 364062 145635.56 + 7.283 0.999994 364062 163840.00 + 7.375 0.999995 364064 187245.71 + 7.375 1.000000 364064 inf +#[Mean = 2.077, StdDeviation = 0.914] +#[Max = 7.372, Total count = 364064] +#[Buckets = 27, SubBuckets = 2048] +---------------------------------------------------------- + 552075 requests in 30.00s, 38.85MB read +Requests/sec: 18402.00 +Transfer/sec: 1.29MB From b42dd118b3cae6bf576e421d71bd6800a5a3b171 Mon Sep 17 00:00:00 2001 From: Osipov_Daniil <334924@niuitmo.ru> Date: Thu, 11 Apr 2024 15:44:22 +0300 Subject: [PATCH 16/23] hw5 code --- .../itmo/test/osipovdaniil/HandleResult.java | 14 + .../test/osipovdaniil/MergeHandleResult.java | 77 ++++ .../vk/itmo/test/osipovdaniil/ServerImpl.java | 394 +++++++++++------- .../test/osipovdaniil/ServiceFactoryImpl.java | 2 +- .../itmo/test/osipovdaniil/ServiceImpl.java | 110 ++++- .../ru/vk/itmo/test/osipovdaniil/Utils.java | 19 + .../dao/LiveFilteringIterator.java | 14 +- .../itmo/test/osipovdaniil/dao/MemTable.java | 10 +- .../dao/MergingEntryIterator.java | 10 +- .../osipovdaniil/dao/ReferenceBaseEntry.java | 10 + .../test/osipovdaniil/dao/ReferenceDao.java | 8 +- .../itmo/test/osipovdaniil/dao/SSTable.java | 26 +- .../test/osipovdaniil/dao/SSTableWriter.java | 17 +- .../itmo/test/osipovdaniil/dao/SSTables.java | 4 +- .../itmo/test/osipovdaniil/dao/TableSet.java | 32 +- .../dao/WeightedPeekingEntryIterator.java | 16 +- 16 files changed, 524 insertions(+), 239 deletions(-) create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/HandleResult.java create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/MergeHandleResult.java create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/Utils.java create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/dao/ReferenceBaseEntry.java diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/HandleResult.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/HandleResult.java new file mode 100644 index 000000000..9ce1e2949 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/HandleResult.java @@ -0,0 +1,14 @@ +package ru.vk.itmo.test.osipovdaniil; + +public record HandleResult(int status, byte[] data, long timestamp) { + + public HandleResult(int status, byte[] data, long timestamp) { + this.status = status; + this.data = data; + this.timestamp = timestamp; + } + + public HandleResult(int status, byte[] data) { + this(status, data, 0); + } +} diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/MergeHandleResult.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/MergeHandleResult.java new file mode 100644 index 000000000..8307fecd4 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/MergeHandleResult.java @@ -0,0 +1,77 @@ +package ru.vk.itmo.test.osipovdaniil; + +import one.nio.http.HttpSession; +import one.nio.http.Response; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.net.HttpURLConnection; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicInteger; + +public class MergeHandleResult { + private static final Logger log = LoggerFactory.getLogger(MergeHandleResult.class); + private final HandleResult[] handleResults; + private final AtomicInteger count; + private final AtomicInteger countValid; + private final int ack; + private final int from; + private final HttpSession session; + + public MergeHandleResult(HttpSession session, int size, int ack) { + this.session = session; + this.handleResults = new HandleResult[size]; + this.count = new AtomicInteger(); + this.countValid = new AtomicInteger(); + this.ack = ack; + this.from = size; + } + + + public boolean add(int index, HandleResult handleResult) { + handleResults[index] = handleResult; + int valid = validateResultStatus(handleResult.status()) ? countValid.getAndIncrement() : countValid.get(); + if (valid >= ack) { + sendResult(); + return true; + } + int get = count.incrementAndGet(); + if (get == from) { + sendResult(); + return true; + } + return false; + } + + private boolean validateResultStatus(final int status) { + return status == HttpURLConnection.HTTP_OK + ||status == HttpURLConnection.HTTP_CREATED + || status == HttpURLConnection.HTTP_ACCEPTED + || status == HttpURLConnection.HTTP_NOT_FOUND; + } + + + private void sendResult() { + HandleResult mergedResult = new HandleResult(HttpURLConnection.HTTP_GATEWAY_TIMEOUT, null); + int count = 0; + for (HandleResult handleResult : handleResults) { + if (validateResultStatus(handleResult.status())) { + count++; + if (mergedResult.timestamp() <= handleResult.timestamp()) { + mergedResult = handleResult; + } + } + } + try { + if (count < ack) { + session.sendResponse(new Response(Response.GATEWAY_TIMEOUT, Response.EMPTY)); + } else { + session.sendResponse(new Response(String.valueOf(mergedResult.status()), mergedResult.data())); + } + } catch (Exception e) { + log.error("Exception during handleRequest", e); + Utils.sendEmptyInternal(session, log); + } + } +} diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java index eae39435a..e0dbfd27c 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java @@ -1,19 +1,21 @@ package ru.vk.itmo.test.osipovdaniil; +import one.nio.async.CustomThreadFactory; import one.nio.http.HttpServer; import one.nio.http.HttpServerConfig; import one.nio.http.HttpSession; -import one.nio.http.Param; import one.nio.http.Path; import one.nio.http.Request; -import one.nio.http.RequestMethod; import one.nio.http.Response; import one.nio.server.AcceptorConfig; import one.nio.util.Hash; +import one.nio.util.Utf8; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import ru.vk.itmo.ServiceConfig; -import ru.vk.itmo.dao.BaseEntry; -import ru.vk.itmo.dao.Entry; +import ru.vk.itmo.test.osipovdaniil.dao.ReferenceBaseEntry; import ru.vk.itmo.test.osipovdaniil.dao.ReferenceDao; + import java.io.IOException; import java.lang.foreign.MemorySegment; import java.lang.foreign.ValueLayout; @@ -22,193 +24,285 @@ import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; -import java.nio.charset.StandardCharsets; -import java.util.List; +import java.time.Duration; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import java.util.concurrent.RejectedExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.function.Function; -import java.util.logging.Logger; +import java.util.concurrent.atomic.AtomicBoolean; public class ServerImpl extends HttpServer { - private static final String ENTITY_PATH = "/v0/entity"; - private static final Integer MAX_THREADS = 64; - private static final String ID = "id="; - private final ExecutorService requestExecutor; - private final List clusterUrls; - private final Logger logger; + private static final String HEADER_REMOTE = "X-flag-remote-server-to-node"; + private static final String HEADER_REMOTE_ONE_NIO_HEADER = HEADER_REMOTE + ": true"; + private static final String HEADER_TIMESTAMP = "X-flag-remote-server-to-node"; + private static final String HEADER_TIMESTAMP_ONE_NIO_HEADER = HEADER_TIMESTAMP + ": "; + private static final Logger log = LoggerFactory.getLogger(ServerImpl.class); + private final static int THREADS = Runtime.getRuntime().availableProcessors(); + private final ExecutorService executorLocal = Executors.newFixedThreadPool(THREADS / 2, + new CustomThreadFactory("local-work")); + private final ExecutorService executorRemote = Executors.newFixedThreadPool(THREADS / 2, + new CustomThreadFactory("remote-work")); private final ReferenceDao dao; - private final String url; + private final ServiceConfig config; private final HttpClient httpClient; - public ServerImpl(final ServiceConfig serviceConfig, ReferenceDao dao) throws IOException { - super(createHttpServerConfig(serviceConfig)); + public ServerImpl(final ServiceConfig config, + final ReferenceDao dao) throws IOException { + super(createServerConfigWithPort(config.selfPort())); this.dao = dao; - this.requestExecutor = Executors.newFixedThreadPool(MAX_THREADS); - this.logger = Logger.getLogger(ServerImpl.class.getName()); - this.clusterUrls = serviceConfig.clusterUrls(); - this.url = serviceConfig.selfUrl(); - this.httpClient = HttpClient.newHttpClient(); + this.config = config; + + + this.httpClient = HttpClient.newBuilder() + .executor(Executors.newFixedThreadPool(THREADS)) + .connectTimeout(Duration.ofMillis(500)) + .version(HttpClient.Version.HTTP_1_1) + .build(); } - private static HttpServerConfig createHttpServerConfig(final ServiceConfig serviceConfig) { - final HttpServerConfig httpServerConfig = new HttpServerConfig(); - final AcceptorConfig acceptorConfig = new AcceptorConfig(); - acceptorConfig.port = serviceConfig.selfPort(); + private static HttpServerConfig createServerConfigWithPort(final int port) { + HttpServerConfig serverConfig = new HttpServerConfig(); + AcceptorConfig acceptorConfig = new AcceptorConfig(); + acceptorConfig.port = port; acceptorConfig.reusePort = true; - httpServerConfig.acceptors = new AcceptorConfig[]{acceptorConfig}; - httpServerConfig.closeSessions = true; - return httpServerConfig; + serverConfig.selectors = Runtime.getRuntime().availableProcessors() / 2; + + serverConfig.acceptors = new AcceptorConfig[]{acceptorConfig}; + serverConfig.closeSessions = true; + return serverConfig; } private boolean validateId(final String id) { return id != null && !id.isEmpty(); } - private Response requestHandle(final String id, final Function request) { + private boolean validateMethod(final int method) { + return method == Request.METHOD_PUT || method == Request.METHOD_DELETE || method == Request.METHOD_GET; + } + + private boolean validateAckFrom(final int ack, final int from) { + return from > 0 && from <= config.clusterUrls().size() && ack <= from && ack > 0; + } + + @Override + public void handleRequest(final Request request, final HttpSession session) throws IOException { + if (!"/v0/entity".equals(request.getPath())) { + session.sendError(Response.BAD_REQUEST, null); + return; + } + if (!validateMethod(request.getMethod())) { + session.sendError(Response.METHOD_NOT_ALLOWED, null); + return; + } + final String id = request.getParameter("id="); if (!validateId(id)) { - return new Response(Response.BAD_REQUEST, ("invalid id: " + id).getBytes(StandardCharsets.UTF_8)); + session.sendError(Response.BAD_REQUEST, null); + return; + } + if (request.getHeader(HEADER_REMOTE_ONE_NIO_HEADER) != null) { + executorLocal.execute(() -> { + try { + final HandleResult local = local(request, id); + final Response response = new Response(String.valueOf(local.status()), local.data()); + response.addHeader(HEADER_TIMESTAMP_ONE_NIO_HEADER + local.timestamp()); + session.sendResponse(response); + } catch (Exception e) { + log.error("Exception during handleRequest", e); + Utils.sendEmptyInternal(session, log); + } + }); + return; + } + final int ack = getInt(request, "ack=", config.clusterUrls().size() / 2 + 1); + final int from = getInt(request, "from=", config.clusterUrls().size()); + if (!validateAckFrom(ack, from)) { + session.sendError(Response.BAD_REQUEST, null); + return; + } + final int[] indexes = getIndexes(id, from); + final MergeHandleResult mergeHandleResult = new MergeHandleResult(session, indexes.length, ack); + for (int i = 0; i < indexes.length; i++) { + int index = indexes[i]; + final String executorNode = config.clusterUrls().get(index); + if (executorNode.equals(config.selfUrl())) { + handleAsync(executorLocal, i, mergeHandleResult, () -> localAsync(request, id)); + } else { + handleAsync(executorRemote, i, mergeHandleResult, () -> remoteAsync(request, executorNode)); + } } - final MemorySegment key = MemorySegment.ofArray(id.getBytes(StandardCharsets.UTF_8)); - return request.apply(key); - } - - private Response handleProxyRequest(final Request request, final String url) throws IOException, - InterruptedException { - final HttpResponse response = processProxyRequest(request, url); - final String statusCode = switch (response.statusCode()) { - case HttpURLConnection.HTTP_OK -> Response.OK; - case HttpURLConnection.HTTP_CREATED -> Response.CREATED; - case HttpURLConnection.HTTP_ACCEPTED -> Response.ACCEPTED; - case HttpURLConnection.HTTP_BAD_REQUEST -> Response.BAD_REQUEST; - case HttpURLConnection.HTTP_NOT_FOUND -> Response.NOT_FOUND; - default -> throw new IllegalStateException("Unexpected response status code: " + response.statusCode()); - }; - return new Response(statusCode, response.body()); - } - - private HttpResponse processProxyRequest(final Request request, final String url) throws IOException, - InterruptedException { - final byte[] rBody = request.getBody(); - final byte[] requestBody = rBody == null ? new byte[0] : rBody; - return httpClient - .send(HttpRequest.newBuilder(URI.create(url + request.getURI())) - .method(request.getMethodName(), HttpRequest.BodyPublishers.ofByteArray(requestBody)) - .build(), HttpResponse.BodyHandlers.ofByteArray()); - } - - private String getTargetUrl(final String id) { - int max = 0; - int maxId = 0; - for (int i = 0; i < clusterUrls.size(); i++) { - int hash = Hash.murmur3(id + i); - if (hash > max) { - max = hash; - maxId = i; + + } + + private int getInt(final Request request, final String param, final int defaultValue) { + int ack; + String ackStr = request.getParameter(param); + if (ackStr == null || ackStr.isBlank()) { + ack = defaultValue; + } else { + try { + ack = Integer.parseInt(ackStr); + } catch (Exception e) { + throw new IllegalArgumentException("parse error (not int)"); } } - return clusterUrls.get(maxId); - } - - @Path(ENTITY_PATH) - @RequestMethod(Request.METHOD_GET) - public Response get(@Param("id") final String id) { - return requestHandle(id, - key -> { - final Entry entry = dao.get(key); - return entry == null - ? new Response(Response.NOT_FOUND, Response.EMPTY) : - Response.ok(entry.value().toArray(ValueLayout.JAVA_BYTE)); - }); - } - - @Path(ENTITY_PATH) - @RequestMethod(Request.METHOD_DELETE) - public Response delete(@Param("id") final String id) { - return requestHandle(id, - key -> { - dao.upsert(new BaseEntry<>(key, null)); - return new Response(Response.ACCEPTED, Response.EMPTY); - }); - } - - @Path(ENTITY_PATH) - @RequestMethod(Request.METHOD_PUT) - public Response put(@Param("id") final String id, final Request value) { - return requestHandle(id, - key -> { - dao.upsert(new BaseEntry<>(key, MemorySegment.ofArray(value.getBody()))); - return new Response(Response.CREATED, Response.EMPTY); - }); - } - - private void handleRequestTask(final Request request, final HttpSession session) { + return ack; + } + + private CompletableFuture remoteAsync(final Request request, final String executorNode) { + return CompletableFuture.supplyAsync(() -> remote(request, executorNode)); + } + + private HandleResult remote(final Request request, final String executorNode) { try { - Response response; - if (!request.getPath().startsWith(ENTITY_PATH)) { - response = new Response(Response.BAD_REQUEST, Response.EMPTY); - session.sendResponse(response); - return; - } - final String targetUrl = getTargetUrl(request.getParameter(ID)); - if (!url.equals(targetUrl)) { - session.sendResponse(handleProxyRequest(request, targetUrl)); + return invokeRemote(executorNode, request); + } catch (IOException e) { + log.info("I/O exception while calling remote node", e); + return new HandleResult(HttpURLConnection.HTTP_INTERNAL_ERROR, Response.EMPTY); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + log.info("Thread interrupted"); + return new HandleResult(HttpURLConnection.HTTP_UNAVAILABLE, Response.EMPTY); + } + + } + + private void handleAsync(final ExecutorService executor, + final int index, + final MergeHandleResult mergeHandleResult, + final ERunnable runnable) { + final AtomicBoolean done = new AtomicBoolean(); + + CompletableFuture completableFuture; + try { + completableFuture = runnable.run(); + } catch (Exception e) { + log.error("Exception during handleRequest", e); + completableFuture = CompletableFuture.supplyAsync( + () -> new HandleResult(HttpURLConnection.HTTP_INTERNAL_ERROR, Response.EMPTY)); + } + completableFuture.whenCompleteAsync((handleResult, throwable) -> { + if (done.get()) { return; } + // throwable != null + done.set(mergeHandleResult.add(index, handleResult)); + }, executor).exceptionally( + throwable -> new HandleResult(HttpURLConnection.HTTP_INTERNAL_ERROR, Response.EMPTY)); + } - final int method = request.getMethod(); - if (method == Request.METHOD_GET) { - response = get(request.getParameter(ID)); - } else if (method == Request.METHOD_DELETE) { - response = delete(request.getParameter(ID)); - } else if (method == Request.METHOD_PUT) { - response = put(request.getParameter(ID), request); - } else { - response = new Response(Response.METHOD_NOT_ALLOWED, Response.EMPTY); - } - session.sendResponse(response); - } catch (IOException | InterruptedException e) { + @Override + public void handleDefault(final Request request, final HttpSession session) throws IOException { + session.sendResponse(new Response(Response.BAD_REQUEST, Response.EMPTY)); + } + + @Path("/v0/status") + public Response status() { + return Response.ok("OK"); + } + + private HandleResult invokeRemote(final String executorNode, final Request request) + throws IOException, InterruptedException { + final HttpRequest httpRequest = HttpRequest.newBuilder(URI.create(executorNode + request.getURI())) + .method( + request.getMethodName(), + request.getBody() == null + ? HttpRequest.BodyPublishers.noBody() + : HttpRequest.BodyPublishers.ofByteArray(request.getBody()) + ) + .header(HEADER_REMOTE, "true") + .timeout(Duration.ofMillis(500)) + .build(); + final HttpResponse httpResponse = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofByteArray()); + final Optional string = httpResponse.headers().firstValue(HEADER_TIMESTAMP); + long timestamp; + if (string.isPresent()) { try { - session.sendResponse(new Response(Response.INTERNAL_ERROR, Response.EMPTY)); - } catch (IOException e1) { - logger.info(e.getMessage()); + timestamp = Long.parseLong(string.get()); + } catch (Exception e) { + log.error("error timestamp parsing\n" + e); + timestamp = 0; } - logger.info("IO or Interrupted exception in execution request: " + request + "\n"); - Thread.currentThread().interrupt(); + } else { + timestamp = 0; } + return new HandleResult(httpResponse.statusCode(), httpResponse.body(), timestamp); } - @Override - public void handleRequest(final Request request, final HttpSession session) throws IOException { - try { - requestExecutor.execute(() -> handleRequestTask(request, session)); - } catch (RejectedExecutionException e) { - logger.info("Execution has been rejected in request: " + request + "\n"); - session.sendError(Response.SERVICE_UNAVAILABLE, ""); + private CompletableFuture localAsync(final Request request, final String id) { + return CompletableFuture.supplyAsync(() -> local(request, id)); + } + + private HandleResult local(final Request request, final String id) { + final long currentTimeMillis = System.currentTimeMillis(); + switch (request.getMethod()) { + case Request.METHOD_GET -> { + final MemorySegment key = MemorySegment.ofArray(Utf8.toBytes(id)); + final ReferenceBaseEntry entry = dao.get(key); + if (entry == null) { + return new HandleResult(HttpURLConnection.HTTP_NOT_FOUND, Response.EMPTY); + } + if (entry.value() == null) { + return new HandleResult(HttpURLConnection.HTTP_NOT_FOUND, Response.EMPTY, entry.timestamp()); + } + return new HandleResult(HttpURLConnection.HTTP_OK, + entry.value().toArray(ValueLayout.JAVA_BYTE), entry.timestamp()); + } + case Request.METHOD_PUT -> { + final MemorySegment key = MemorySegment.ofArray(Utf8.toBytes(id)); + final MemorySegment value = MemorySegment.ofArray(request.getBody()); + dao.upsert(new ReferenceBaseEntry<>(key, value, currentTimeMillis)); + return new HandleResult(HttpURLConnection.HTTP_CREATED, Response.EMPTY); + } + case Request.METHOD_DELETE -> { + final MemorySegment key = MemorySegment.ofArray(Utf8.toBytes(id)); + dao.upsert(new ReferenceBaseEntry<>(key, null, currentTimeMillis)); + return new HandleResult(HttpURLConnection.HTTP_ACCEPTED, Response.EMPTY); + } + default -> { + return new HandleResult(HttpURLConnection.HTTP_BAD_METHOD, Response.EMPTY); + } } } - void shutdownAndAwaitTermination(ExecutorService pool) { - try { - if (!pool.awaitTermination(60, TimeUnit.MILLISECONDS)) { - pool.shutdownNow(); - if (!pool.awaitTermination(60, TimeUnit.MILLISECONDS)) { - logger.info("Pool did not terminate"); + // count <= config.clusterUrls().size() + private int[] getIndexes(final String id, final int count) { + assert count < 5; + + int[] result = new int[count]; + int[] maxHashs = new int[count]; + + for (int i = 0; i < count; i++) { + String url = config.clusterUrls().get(i); + int hash = Hash.murmur3(url + id); + result[i] = i; + maxHashs[i] = hash; + } + + for (int i = count; i < config.clusterUrls().size(); i++) { + String url = config.clusterUrls().get(i); + int hash = Hash.murmur3(url + id); + for (int j = 0; j < maxHashs.length; j++) { + int maxHash = maxHashs[j]; + if (maxHash < hash) { + maxHashs[j] = hash; + result[j] = i; + break; } } - } catch (InterruptedException ie) { - pool.shutdownNow(); - Thread.currentThread().interrupt(); } + return result; + } + + private interface ERunnable { + CompletableFuture run() throws Exception; } @Override public synchronized void stop() { super.stop(); - shutdownAndAwaitTermination(requestExecutor); - httpClient.close(); + ServiceImpl.shutdownAndAwaitTermination(executorLocal); + ServiceImpl.shutdownAndAwaitTermination(executorRemote); } -} +} \ No newline at end of file diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/ServiceFactoryImpl.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/ServiceFactoryImpl.java index 5b181552e..76fd2c4b1 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/ServiceFactoryImpl.java +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/ServiceFactoryImpl.java @@ -4,7 +4,7 @@ import ru.vk.itmo.ServiceConfig; import ru.vk.itmo.test.ServiceFactory; -@ServiceFactory(stage = 3) +@ServiceFactory(stage = 5) public class ServiceFactoryImpl implements ServiceFactory.Factory { @Override diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/ServiceImpl.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/ServiceImpl.java index e9f1cc3ab..1249ae5f6 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/ServiceImpl.java +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/ServiceImpl.java @@ -3,46 +3,116 @@ import ru.vk.itmo.Service; import ru.vk.itmo.ServiceConfig; import ru.vk.itmo.dao.Config; +import ru.vk.itmo.test.ServiceFactory; import ru.vk.itmo.test.osipovdaniil.dao.ReferenceDao; import java.io.IOException; -import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.TimeUnit; public class ServiceImpl implements Service { - public static final long FLUSH_THRESHOLD_BYTES = 1024L * 1024; - private ServerImpl server; - private final ServiceConfig serviceConfig; - private ReferenceDao dao; + private static final long FLUSHING_THRESHOLD_BYTES = 1024 * 1024; - private final Config daoConfig; + private static final String LOCALHOST_PREFIX = "http://localhost:"; - public ServiceImpl(final ServiceConfig serviceConfig) { - this.serviceConfig = serviceConfig; - this.daoConfig = createDaoConfig(serviceConfig); - } + private final ServiceConfig config; - private static Config createDaoConfig(final ServiceConfig config) { - return new Config(config.workingDir(), FLUSH_THRESHOLD_BYTES); + private ReferenceDao dao; + private ServerImpl server; + private boolean stopped; + public ServiceImpl(ServiceConfig config) { + this.config = config; } @Override - public CompletableFuture start() throws IOException { - this.dao = new ReferenceDao(daoConfig); - this.server = new ServerImpl(serviceConfig, dao); + public synchronized CompletableFuture start() throws IOException { + dao = new ReferenceDao(new Config(config.workingDir(), FLUSHING_THRESHOLD_BYTES)); + server = new ServerImpl(config, dao); server.start(); + stopped = false; return CompletableFuture.completedFuture(null); } @Override - public CompletableFuture stop() { - server.stop(); + public synchronized CompletableFuture stop() throws IOException { + if (stopped) { + return CompletableFuture.completedFuture(null); + } try { + server.stop(); + + } finally { dao.close(); - } catch (IOException e) { - throw new UncheckedIOException(e); } + stopped = true; return CompletableFuture.completedFuture(null); } -} + + public static void shutdownAndAwaitTermination(ExecutorService pool) { + pool.shutdown(); + try { + if (!pool.awaitTermination(60, TimeUnit.SECONDS)) { + pool.shutdownNow(); + if (!pool.awaitTermination(60, TimeUnit.SECONDS)) { + System.err.println("Pool did not terminate"); + } + } + } catch (InterruptedException ex) { + pool.shutdownNow(); + Thread.currentThread().interrupt(); + } + } + + @ServiceFactory(stage = 4) + public static class Factory implements ServiceFactory.Factory { + + @Override + public Service create(ServiceConfig config) { + return new ServiceImpl(config); + } + } + + public static void main(String[] args) throws IOException { + //port -> url + Map nodes = new HashMap<>(); + int nodePort = 8080; + for (int i = 0; i < 3; i++) { + nodes.put(nodePort, LOCALHOST_PREFIX + nodePort); + nodePort += 10; + } + + List clusterUrls = new ArrayList<>(nodes.values()); + List clusterConfs = new ArrayList<>(); + for (Map.Entry entry : nodes.entrySet()) { + int port = entry.getKey(); + String url = entry.getValue(); + Path path = Paths.get("tmp/db/" + port); + Files.createDirectories(path); + ServiceConfig serviceConfig = new ServiceConfig(port, + url, + clusterUrls, + path); + clusterConfs.add(serviceConfig); + } + + for (ServiceConfig serviceConfig : clusterConfs) { + ServiceImpl instance = new ServiceImpl(serviceConfig); + try { + instance.start().get(1, TimeUnit.SECONDS); + } catch (InterruptedException | ExecutionException | TimeoutException e) { + throw new RuntimeException(e); + } + } + } +} \ No newline at end of file diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/Utils.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/Utils.java new file mode 100644 index 000000000..c15fb3d7b --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/Utils.java @@ -0,0 +1,19 @@ +package ru.vk.itmo.test.osipovdaniil; + +import one.nio.http.HttpSession; +import one.nio.http.Response; + +import org.slf4j.Logger; + +import java.io.IOException; + +public class Utils { + public static void sendEmptyInternal(final HttpSession session, final Logger logger) { + try { + session.sendResponse(new Response(Response.INTERNAL_ERROR, Response.EMPTY)); + } catch (IOException e) { + logger.error("Exception while sending close connection", e); + session.scheduleClose(); + } + } +} diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/LiveFilteringIterator.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/LiveFilteringIterator.java index c30b99f54..dec39e11c 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/LiveFilteringIterator.java +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/LiveFilteringIterator.java @@ -11,18 +11,18 @@ * * @author incubos */ -final class LiveFilteringIterator implements Iterator> { - private final Iterator> delegate; - private Entry next; +final class LiveFilteringIterator implements Iterator> { + private final Iterator> delegate; + private ReferenceBaseEntry next; - LiveFilteringIterator(final Iterator> delegate) { + LiveFilteringIterator(final Iterator> delegate) { this.delegate = delegate; skipTombstones(); } private void skipTombstones() { while (delegate.hasNext()) { - final Entry entry = delegate.next(); + final ReferenceBaseEntry entry = delegate.next(); if (entry.value() != null) { this.next = entry; break; @@ -36,13 +36,13 @@ public boolean hasNext() { } @Override - public Entry next() { + public ReferenceBaseEntry next() { if (!hasNext()) { throw new NoSuchElementException(); } // Consume - final Entry result = next; + final ReferenceBaseEntry result = next; next = null; skipTombstones(); diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/MemTable.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/MemTable.java index aa38f2feb..e4a3b1724 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/MemTable.java +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/MemTable.java @@ -1,7 +1,5 @@ package ru.vk.itmo.test.osipovdaniil.dao; -import ru.vk.itmo.dao.Entry; - import java.lang.foreign.MemorySegment; import java.util.Iterator; import java.util.NavigableMap; @@ -13,7 +11,7 @@ * @author incubos */ final class MemTable { - private final NavigableMap> map = + private final NavigableMap> map = new ConcurrentSkipListMap<>( MemorySegmentComparator.INSTANCE); @@ -21,7 +19,7 @@ boolean isEmpty() { return map.isEmpty(); } - Iterator> get( + Iterator> get( final MemorySegment from, final MemorySegment to) { if (from == null && to == null) { @@ -39,11 +37,11 @@ Iterator> get( } } - Entry get(final MemorySegment key) { + ReferenceBaseEntry get(final MemorySegment key) { return map.get(key); } - Entry upsert(final Entry entry) { + ReferenceBaseEntry upsert(final ReferenceBaseEntry entry) { return map.put(entry.key(), entry); } } diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/MergingEntryIterator.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/MergingEntryIterator.java index 0d5343f39..0659679f2 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/MergingEntryIterator.java +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/MergingEntryIterator.java @@ -1,7 +1,5 @@ package ru.vk.itmo.test.osipovdaniil.dao; -import ru.vk.itmo.dao.Entry; - import java.lang.foreign.MemorySegment; import java.util.Iterator; import java.util.List; @@ -14,7 +12,7 @@ * * @author incubos */ -final class MergingEntryIterator implements Iterator> { +final class MergingEntryIterator implements Iterator> { private final Queue iterators; MergingEntryIterator(final List iterators) { @@ -29,13 +27,13 @@ public boolean hasNext() { } @Override - public Entry next() { + public ReferenceBaseEntry next() { if (!hasNext()) { throw new NoSuchElementException(); } final WeightedPeekingEntryIterator top = iterators.remove(); - final Entry result = top.next(); + final ReferenceBaseEntry result = top.next(); if (top.hasNext()) { // Not exhausted @@ -51,7 +49,7 @@ public Entry next() { } // Skip entries with the same key - final Entry entry = iterator.peek(); + final ReferenceBaseEntry entry = iterator.peek(); if (MemorySegmentComparator.INSTANCE.compare(result.key(), entry.key()) != 0) { // Reached another key break; diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/ReferenceBaseEntry.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/ReferenceBaseEntry.java new file mode 100644 index 000000000..eb7c79e82 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/ReferenceBaseEntry.java @@ -0,0 +1,10 @@ +package ru.vk.itmo.test.osipovdaniil.dao; + +import ru.vk.itmo.dao.Entry; + +public record ReferenceBaseEntry(D key, D value, long timestamp) implements Entry { + @Override + public String toString() { + return "{" + key + ":" + value + "," + timestamp + "}"; + } +} \ No newline at end of file diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/ReferenceDao.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/ReferenceDao.java index 5ebda7ae3..fdce16822 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/ReferenceDao.java +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/ReferenceDao.java @@ -22,7 +22,7 @@ * * @author incubos */ -public class ReferenceDao implements Dao> { +public class ReferenceDao implements Dao> { private final Config config; private final Arena arena; @@ -63,7 +63,7 @@ public ReferenceDao(final Config config) throws IOException { } @Override - public Iterator> get( + public Iterator> get( final MemorySegment from, final MemorySegment to) { return new LiveFilteringIterator( @@ -73,13 +73,13 @@ public Iterator> get( } @Override - public Entry get(final MemorySegment key) { + public ReferenceBaseEntry get(final MemorySegment key) { // Without lock, just snapshot of table set return tableSet.get(key); } @Override - public void upsert(final Entry entry) { + public void upsert(final ReferenceBaseEntry entry) { final boolean autoFlush; lock.readLock().lock(); try { diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/SSTable.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/SSTable.java index 1c08d2242..98176bedc 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/SSTable.java +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/SSTable.java @@ -1,8 +1,5 @@ package ru.vk.itmo.test.osipovdaniil.dao; -import ru.vk.itmo.dao.BaseEntry; -import ru.vk.itmo.dao.Entry; - import java.lang.foreign.MemorySegment; import java.lang.foreign.ValueLayout; import java.util.Collections; @@ -88,7 +85,7 @@ private long getLength(final long offset) { offset); } - Iterator> get( + Iterator> get( final MemorySegment from, final MemorySegment to) { assert from == null || to == null || MemorySegmentComparator.INSTANCE.compare(from, to) <= 0; @@ -134,7 +131,7 @@ Iterator> get( return new SliceIterator(fromOffset, toOffset); } - Entry get(final MemorySegment key) { + ReferenceBaseEntry get(final MemorySegment key) { final long entry = entryBinarySearch(key); if (entry < 0) { return null; @@ -143,20 +140,23 @@ Entry get(final MemorySegment key) { // Skip key (will reuse the argument) long offset = entryOffset(entry); offset += Long.BYTES + key.byteSize(); + // Extract timestamp + long timestamp = data.get(ValueLayout.OfLong.JAVA_LONG_UNALIGNED, offset); + offset += Long.BYTES; // Extract value length final long valueLength = getLength(offset); if (valueLength == SSTables.TOMBSTONE_VALUE_LENGTH) { // Tombstone encountered - return new BaseEntry<>(key, null); + return new ReferenceBaseEntry<>(key, null, timestamp); } else { // Get value offset += Long.BYTES; final MemorySegment value = data.asSlice(offset, valueLength); - return new BaseEntry<>(key, value); + return new ReferenceBaseEntry<>(key, value, timestamp); } } - private final class SliceIterator implements Iterator> { + private final class SliceIterator implements Iterator> { private long offset; private final long toOffset; @@ -173,7 +173,7 @@ public boolean hasNext() { } @Override - public Entry next() { + public ReferenceBaseEntry next() { if (!hasNext()) { throw new NoSuchElementException(); } @@ -186,6 +186,10 @@ public Entry next() { final MemorySegment key = data.asSlice(offset, keyLength); offset += keyLength; + // Read timestamp + long timestamp = data.get(ValueLayout.OfLong.JAVA_LONG_UNALIGNED, offset); + offset += Long.BYTES; + // Read value length final long valueLength = getLength(offset); offset += Long.BYTES; @@ -193,11 +197,11 @@ public Entry next() { // Read value if (valueLength == SSTables.TOMBSTONE_VALUE_LENGTH) { // Tombstone encountered - return new BaseEntry<>(key, null); + return new ReferenceBaseEntry<>(key, null, timestamp); } else { final MemorySegment value = data.asSlice(offset, valueLength); offset += valueLength; - return new BaseEntry<>(key, value); + return new ReferenceBaseEntry<>(key, value, timestamp); } } } diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/SSTableWriter.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/SSTableWriter.java index 920a0bbb5..caa5f2b70 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/SSTableWriter.java +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/SSTableWriter.java @@ -1,7 +1,5 @@ package ru.vk.itmo.test.osipovdaniil.dao; -import ru.vk.itmo.dao.Entry; - import java.io.BufferedOutputStream; import java.io.FileOutputStream; import java.io.IOException; @@ -15,7 +13,7 @@ import java.util.Iterator; /** - * Writes {@link Entry} {@link Iterator} to SSTable on disk. + * Writes {@link ReferenceBaseEntry} {@link Iterator} to SSTable on disk. * *

Index file {@code .index} contains {@code long} offsets to entries in data file: * {@code [offset0, offset1, ...]} @@ -40,7 +38,7 @@ final class SSTableWriter { void write( final Path baseDir, final int sequence, - final Iterator> entries) throws IOException { + final Iterator> entries) throws IOException { // Write to temporary files final Path tempIndexName = SSTables.tempIndexName(baseDir, sequence); final Path tempDataName = SSTables.tempDataName(baseDir, sequence); @@ -71,7 +69,7 @@ void write( writeLong(entryOffset, index); // Then write the entry - final Entry entry = entries.next(); + final ReferenceBaseEntry entry = entries.next(); entryOffset += writeEntry(entry, data); } } @@ -127,15 +125,16 @@ private void writeSegment( } /** - * Writes {@link Entry} to {@link FileChannel}. + * Writes {@link ReferenceBaseEntry} to {@link FileChannel}. * * @return written bytes */ private long writeEntry( - final Entry entry, + final ReferenceBaseEntry entry, final OutputStream os) throws IOException { final MemorySegment key = entry.key(); final MemorySegment value = entry.value(); + final long timestamp = entry.timestamp(); long result = 0L; // Key size @@ -146,6 +145,10 @@ private long writeEntry( writeSegment(key, os); result += key.byteSize(); + // timestamp + writeLong(timestamp, os); + result += Long.BYTES; + // Value size and possibly value if (value == null) { // Tombstone diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/SSTables.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/SSTables.java index 6aaeb776a..75b0adb6b 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/SSTables.java +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/SSTables.java @@ -51,7 +51,9 @@ static Path tempIndexName( return baseDir.resolve(sequence + INDEX_SUFFIX + TEMP_SUFFIX); } - static Path tempDataName(final Path baseDir, final int sequence) { + static Path tempDataName( + final Path baseDir, + final int sequence) { return baseDir.resolve(sequence + DATA_SUFFIX + TEMP_SUFFIX); } diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/TableSet.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/TableSet.java index 98771eba5..7922c89c8 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/TableSet.java +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/TableSet.java @@ -1,7 +1,5 @@ package ru.vk.itmo.test.osipovdaniil.dao; -import ru.vk.itmo.dao.Entry; - import java.lang.foreign.MemorySegment; import java.util.ArrayList; import java.util.Collections; @@ -98,14 +96,14 @@ TableSet compacted( newSsTables); } - Iterator> get( + Iterator> get( final MemorySegment from, final MemorySegment to) { final List iterators = new ArrayList<>(2 + ssTables.size()); // MemTable goes first - final Iterator> memTableIterator = + final Iterator> memTableIterator = memTable.get(from, to); if (memTableIterator.hasNext()) { iterators.add( @@ -116,7 +114,7 @@ Iterator> get( // Then goes flushing if (flushingTable != null) { - final Iterator> flushingIterator = + final Iterator> flushingIterator = flushingTable.get(from, to); if (flushingIterator.hasNext()) { iterators.add( @@ -129,7 +127,7 @@ Iterator> get( // Then go all the SSTables for (int i = 0; i < ssTables.size(); i++) { final SSTable ssTable = ssTables.get(i); - final Iterator> ssTableIterator = + final Iterator> ssTableIterator = ssTable.get(from, to); if (ssTableIterator.hasNext()) { iterators.add( @@ -146,14 +144,14 @@ Iterator> get( }; } - Entry get(final MemorySegment key) { + ReferenceBaseEntry get(final MemorySegment key) { // Slightly optimized version not to pollute the heap // First check MemTable - Entry result = memTable.get(key); + ReferenceBaseEntry result = memTable.get(key); if (result != null) { // Transform tombstone - return swallowTombstone(result); + return result; } // Then check flushing @@ -161,7 +159,7 @@ Entry get(final MemorySegment key) { result = flushingTable.get(key); if (result != null) { // Transform tombstone - return swallowTombstone(result); + return result; } } @@ -170,7 +168,7 @@ Entry get(final MemorySegment key) { result = ssTable.get(key); if (result != null) { // Transform tombstone - return swallowTombstone(result); + return result; } } @@ -178,21 +176,21 @@ Entry get(final MemorySegment key) { return null; } - private static Entry swallowTombstone(final Entry entry) { - return entry.value() == null ? null : entry; - } +// private static ReferenceBaseEntry swallowTombstone(final ReferenceBaseEntry entry) { +// return entry.value() == null ? null : entry; +// } - Entry upsert(final Entry entry) { + ReferenceBaseEntry upsert(final ReferenceBaseEntry entry) { return memTable.upsert(entry); } - Iterator> allSSTableEntries() { + Iterator> allSSTableEntries() { final List iterators = new ArrayList<>(ssTables.size()); for (int i = 0; i < ssTables.size(); i++) { final SSTable ssTable = ssTables.get(i); - final Iterator> ssTableIterator = + final Iterator> ssTableIterator = ssTable.get(null, null); iterators.add( new WeightedPeekingEntryIterator( diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/WeightedPeekingEntryIterator.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/WeightedPeekingEntryIterator.java index 91f299d9c..08d3c9015 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/WeightedPeekingEntryIterator.java +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/WeightedPeekingEntryIterator.java @@ -1,7 +1,5 @@ package ru.vk.itmo.test.osipovdaniil.dao; -import ru.vk.itmo.dao.Entry; - import java.lang.foreign.MemorySegment; import java.util.Iterator; import java.util.NoSuchElementException; @@ -12,15 +10,15 @@ * @author incubos */ final class WeightedPeekingEntryIterator - implements Iterator>, + implements Iterator>, Comparable { private final int weight; - private final Iterator> delegate; - private Entry next; + private final Iterator> delegate; + private ReferenceBaseEntry next; WeightedPeekingEntryIterator( final int weight, - final Iterator> delegate) { + final Iterator> delegate) { this.weight = weight; this.delegate = delegate; this.next = delegate.hasNext() ? delegate.next() : null; @@ -32,17 +30,17 @@ public boolean hasNext() { } @Override - public Entry next() { + public ReferenceBaseEntry next() { if (!hasNext()) { throw new NoSuchElementException(); } - final Entry result = next; + final ReferenceBaseEntry result = next; next = delegate.hasNext() ? delegate.next() : null; return result; } - Entry peek() { + ReferenceBaseEntry peek() { if (!hasNext()) { throw new NoSuchElementException(); } From c67d945c93dbfa0b27b4a084bf9e398ebfa012d8 Mon Sep 17 00:00:00 2001 From: Osipov_Daniil <334924@niuitmo.ru> Date: Thu, 11 Apr 2024 16:04:13 +0300 Subject: [PATCH 17/23] hw5 codeclimate1 --- .../vk/itmo/test/osipovdaniil/MergeHandleResult.java | 12 ++++-------- .../ru/vk/itmo/test/osipovdaniil/ServerImpl.java | 8 +++----- .../ru/vk/itmo/test/osipovdaniil/ServiceImpl.java | 11 ++++++++--- .../java/ru/vk/itmo/test/osipovdaniil/Utils.java | 3 +-- .../ru/vk/itmo/test/osipovdaniil/dao/TableSet.java | 5 ----- 5 files changed, 16 insertions(+), 23 deletions(-) diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/MergeHandleResult.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/MergeHandleResult.java index 8307fecd4..6482076e1 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/MergeHandleResult.java +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/MergeHandleResult.java @@ -6,8 +6,6 @@ import org.slf4j.LoggerFactory; import java.net.HttpURLConnection; -import java.util.List; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicInteger; public class MergeHandleResult { @@ -28,7 +26,6 @@ public MergeHandleResult(HttpSession session, int size, int ack) { this.from = size; } - public boolean add(int index, HandleResult handleResult) { handleResults[index] = handleResult; int valid = validateResultStatus(handleResult.status()) ? countValid.getAndIncrement() : countValid.get(); @@ -46,25 +43,24 @@ public boolean add(int index, HandleResult handleResult) { private boolean validateResultStatus(final int status) { return status == HttpURLConnection.HTTP_OK - ||status == HttpURLConnection.HTTP_CREATED + || status == HttpURLConnection.HTTP_CREATED || status == HttpURLConnection.HTTP_ACCEPTED || status == HttpURLConnection.HTTP_NOT_FOUND; } - private void sendResult() { HandleResult mergedResult = new HandleResult(HttpURLConnection.HTTP_GATEWAY_TIMEOUT, null); - int count = 0; + int cnt = 0; for (HandleResult handleResult : handleResults) { if (validateResultStatus(handleResult.status())) { - count++; + cnt++; if (mergedResult.timestamp() <= handleResult.timestamp()) { mergedResult = handleResult; } } } try { - if (count < ack) { + if (cnt < ack) { session.sendResponse(new Response(Response.GATEWAY_TIMEOUT, Response.EMPTY)); } else { session.sendResponse(new Response(String.valueOf(mergedResult.status()), mergedResult.data())); diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java index e0dbfd27c..95492df57 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java @@ -38,7 +38,7 @@ public class ServerImpl extends HttpServer { private static final String HEADER_TIMESTAMP = "X-flag-remote-server-to-node"; private static final String HEADER_TIMESTAMP_ONE_NIO_HEADER = HEADER_TIMESTAMP + ": "; private static final Logger log = LoggerFactory.getLogger(ServerImpl.class); - private final static int THREADS = Runtime.getRuntime().availableProcessors(); + private static final int THREADS = Runtime.getRuntime().availableProcessors(); private final ExecutorService executorLocal = Executors.newFixedThreadPool(THREADS / 2, new CustomThreadFactory("local-work")); @@ -53,8 +53,6 @@ public ServerImpl(final ServiceConfig config, super(createServerConfigWithPort(config.selfPort())); this.dao = dao; this.config = config; - - this.httpClient = HttpClient.newBuilder() .executor(Executors.newFixedThreadPool(THREADS)) .connectTimeout(Duration.ofMillis(500)) @@ -296,7 +294,7 @@ private int[] getIndexes(final String id, final int count) { } private interface ERunnable { - CompletableFuture run() throws Exception; + CompletableFuture run() throws IOException; } @Override @@ -305,4 +303,4 @@ public synchronized void stop() { ServiceImpl.shutdownAndAwaitTermination(executorLocal); ServiceImpl.shutdownAndAwaitTermination(executorRemote); } -} \ No newline at end of file +} diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/ServiceImpl.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/ServiceImpl.java index 1249ae5f6..3ef8d2b5d 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/ServiceImpl.java +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/ServiceImpl.java @@ -7,6 +7,7 @@ import ru.vk.itmo.test.osipovdaniil.dao.ReferenceDao; import java.io.IOException; +import java.io.UncheckedIOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -17,8 +18,8 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; -import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; public class ServiceImpl implements Service { @@ -31,6 +32,7 @@ public class ServiceImpl implements Service { private ReferenceDao dao; private ServerImpl server; private boolean stopped; + public ServiceImpl(ServiceConfig config) { this.config = config; } @@ -110,9 +112,12 @@ public static void main(String[] args) throws IOException { ServiceImpl instance = new ServiceImpl(serviceConfig); try { instance.start().get(1, TimeUnit.SECONDS); - } catch (InterruptedException | ExecutionException | TimeoutException e) { + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException(e); + } catch (ExecutionException | TimeoutException e) { throw new RuntimeException(e); } } } -} \ No newline at end of file +} diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/Utils.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/Utils.java index c15fb3d7b..9b92651fa 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/Utils.java +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/Utils.java @@ -2,12 +2,11 @@ import one.nio.http.HttpSession; import one.nio.http.Response; - import org.slf4j.Logger; import java.io.IOException; -public class Utils { +public final class Utils { public static void sendEmptyInternal(final HttpSession session, final Logger logger) { try { session.sendResponse(new Response(Response.INTERNAL_ERROR, Response.EMPTY)); diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/TableSet.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/TableSet.java index 7922c89c8..b80b7b5c5 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/TableSet.java +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/TableSet.java @@ -171,15 +171,10 @@ ReferenceBaseEntry get(final MemorySegment key) { return result; } } - // Nothing found return null; } -// private static ReferenceBaseEntry swallowTombstone(final ReferenceBaseEntry entry) { -// return entry.value() == null ? null : entry; -// } - ReferenceBaseEntry upsert(final ReferenceBaseEntry entry) { return memTable.upsert(entry); } From a2aadf330c427dd987011d956eaaed60f2494bee Mon Sep 17 00:00:00 2001 From: Osipov_Daniil <334924@niuitmo.ru> Date: Thu, 11 Apr 2024 16:12:45 +0300 Subject: [PATCH 18/23] hw5 codeclimate 2 --- .../vk/itmo/test/osipovdaniil/ServerImpl.java | 19 +++++- .../itmo/test/osipovdaniil/ServiceImpl.java | 63 ------------------- .../ru/vk/itmo/test/osipovdaniil/Utils.java | 4 ++ .../osipovdaniil/dao/ReferenceBaseEntry.java | 2 +- 4 files changed, 22 insertions(+), 66 deletions(-) diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java index 95492df57..4e26ddc9d 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java @@ -29,6 +29,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; public class ServerImpl extends HttpServer { @@ -297,10 +298,24 @@ private interface ERunnable { CompletableFuture run() throws IOException; } + private void shutdownAndAwaitTermination(ExecutorService pool) { + try { + if (!pool.awaitTermination(60, TimeUnit.MILLISECONDS)) { + pool.shutdownNow(); + if (!pool.awaitTermination(60, TimeUnit.MILLISECONDS)) { + log.info("Pool did not terminate"); + } + } + } catch (InterruptedException ie) { + pool.shutdownNow(); + Thread.currentThread().interrupt(); + } + } + @Override public synchronized void stop() { super.stop(); - ServiceImpl.shutdownAndAwaitTermination(executorLocal); - ServiceImpl.shutdownAndAwaitTermination(executorRemote); + shutdownAndAwaitTermination(executorLocal); + shutdownAndAwaitTermination(executorRemote); } } diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/ServiceImpl.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/ServiceImpl.java index 3ef8d2b5d..e879f3c49 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/ServiceImpl.java +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/ServiceImpl.java @@ -7,26 +7,14 @@ import ru.vk.itmo.test.osipovdaniil.dao.ReferenceDao; import java.io.IOException; -import java.io.UncheckedIOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; public class ServiceImpl implements Service { private static final long FLUSHING_THRESHOLD_BYTES = 1024 * 1024; - private static final String LOCALHOST_PREFIX = "http://localhost:"; - private final ServiceConfig config; private ReferenceDao dao; @@ -61,21 +49,6 @@ public synchronized CompletableFuture stop() throws IOException { return CompletableFuture.completedFuture(null); } - public static void shutdownAndAwaitTermination(ExecutorService pool) { - pool.shutdown(); - try { - if (!pool.awaitTermination(60, TimeUnit.SECONDS)) { - pool.shutdownNow(); - if (!pool.awaitTermination(60, TimeUnit.SECONDS)) { - System.err.println("Pool did not terminate"); - } - } - } catch (InterruptedException ex) { - pool.shutdownNow(); - Thread.currentThread().interrupt(); - } - } - @ServiceFactory(stage = 4) public static class Factory implements ServiceFactory.Factory { @@ -84,40 +57,4 @@ public Service create(ServiceConfig config) { return new ServiceImpl(config); } } - - public static void main(String[] args) throws IOException { - //port -> url - Map nodes = new HashMap<>(); - int nodePort = 8080; - for (int i = 0; i < 3; i++) { - nodes.put(nodePort, LOCALHOST_PREFIX + nodePort); - nodePort += 10; - } - - List clusterUrls = new ArrayList<>(nodes.values()); - List clusterConfs = new ArrayList<>(); - for (Map.Entry entry : nodes.entrySet()) { - int port = entry.getKey(); - String url = entry.getValue(); - Path path = Paths.get("tmp/db/" + port); - Files.createDirectories(path); - ServiceConfig serviceConfig = new ServiceConfig(port, - url, - clusterUrls, - path); - clusterConfs.add(serviceConfig); - } - - for (ServiceConfig serviceConfig : clusterConfs) { - ServiceImpl instance = new ServiceImpl(serviceConfig); - try { - instance.start().get(1, TimeUnit.SECONDS); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - throw new RuntimeException(e); - } catch (ExecutionException | TimeoutException e) { - throw new RuntimeException(e); - } - } - } } diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/Utils.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/Utils.java index 9b92651fa..970b8ccd1 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/Utils.java +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/Utils.java @@ -7,6 +7,10 @@ import java.io.IOException; public final class Utils { + + private Utils() { + } + public static void sendEmptyInternal(final HttpSession session, final Logger logger) { try { session.sendResponse(new Response(Response.INTERNAL_ERROR, Response.EMPTY)); diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/ReferenceBaseEntry.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/ReferenceBaseEntry.java index eb7c79e82..9e0a60a4e 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/ReferenceBaseEntry.java +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/dao/ReferenceBaseEntry.java @@ -7,4 +7,4 @@ public record ReferenceBaseEntry(D key, D value, long timestamp) implements E public String toString() { return "{" + key + ":" + value + "," + timestamp + "}"; } -} \ No newline at end of file +} From 14d7b58d667ec02952b1fe2e0169ab3a433d7c9e Mon Sep 17 00:00:00 2001 From: Osipov_Daniil <334924@niuitmo.ru> Date: Thu, 11 Apr 2024 16:16:04 +0300 Subject: [PATCH 19/23] hw5 codeclimate 3 --- src/main/java/ru/vk/itmo/test/osipovdaniil/ServiceImpl.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/ServiceImpl.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/ServiceImpl.java index e879f3c49..ff4eeeea4 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/ServiceImpl.java +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/ServiceImpl.java @@ -8,8 +8,6 @@ import java.io.IOException; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.TimeUnit; public class ServiceImpl implements Service { From 36669a4c65862b92631f2f5f90b0c23234d95b7e Mon Sep 17 00:00:00 2001 From: sbread Date: Tue, 30 Apr 2024 02:36:23 +0300 Subject: [PATCH 20/23] report5 --- .../report5/asyncprof/get_alloc_prof.html | 3125 +++++ .../report5/asyncprof/get_cpu_prof.html | 9911 +++++++++++++++ .../report5/asyncprof/get_lock_prof.html | 1066 ++ .../report5/asyncprof/put_alloc_prof.html | 3166 +++++ .../report5/asyncprof/put_cpu_prof.html | 10526 ++++++++++++++++ .../report5/asyncprof/put_lock_prof.html | 1046 ++ .../itmo/test/osipovdaniil/report5/report5.md | 49 + .../vk/itmo/test/osipovdaniil/report5/wrk/get | 121 + .../vk/itmo/test/osipovdaniil/report5/wrk/put | 117 + .../itmo/test/osipovdaniil/scripts/delete.lua | 4 +- .../vk/itmo/test/osipovdaniil/scripts/get.lua | 4 +- .../vk/itmo/test/osipovdaniil/scripts/put.lua | 4 +- 12 files changed, 29133 insertions(+), 6 deletions(-) create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/report5/asyncprof/get_alloc_prof.html create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/report5/asyncprof/get_cpu_prof.html create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/report5/asyncprof/get_lock_prof.html create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/report5/asyncprof/put_alloc_prof.html create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/report5/asyncprof/put_cpu_prof.html create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/report5/asyncprof/put_lock_prof.html create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/report5/report5.md create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/report5/wrk/get create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/report5/wrk/put diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/asyncprof/get_alloc_prof.html b/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/asyncprof/get_alloc_prof.html new file mode 100644 index 000000000..96cb331a1 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/asyncprof/get_alloc_prof.html @@ -0,0 +1,3125 @@ + + + + + + + +

Allocation profile

+
  
+
Produced by async-profiler
+ +
+

+

Matched:

+ diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/asyncprof/get_cpu_prof.html b/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/asyncprof/get_cpu_prof.html new file mode 100644 index 000000000..207e31a50 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/asyncprof/get_cpu_prof.html @@ -0,0 +1,9911 @@ + + + + + + + +

CPU profile

+
  
+
Produced by async-profiler
+ +
+

+

Matched:

+ diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/asyncprof/get_lock_prof.html b/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/asyncprof/get_lock_prof.html new file mode 100644 index 000000000..3bd9787a2 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/asyncprof/get_lock_prof.html @@ -0,0 +1,1066 @@ + + + + + + + +

Lock profile

+
  
+
Produced by async-profiler
+ +
+

+

Matched:

+ diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/asyncprof/put_alloc_prof.html b/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/asyncprof/put_alloc_prof.html new file mode 100644 index 000000000..7dbc22b49 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/asyncprof/put_alloc_prof.html @@ -0,0 +1,3166 @@ + + + + + + + +

Allocation profile

+
  
+
Produced by async-profiler
+ +
+

+

Matched:

+ diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/asyncprof/put_cpu_prof.html b/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/asyncprof/put_cpu_prof.html new file mode 100644 index 000000000..a65351af9 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/asyncprof/put_cpu_prof.html @@ -0,0 +1,10526 @@ + + + + + + + +

CPU profile

+
  
+
Produced by async-profiler
+ +
+

+

Matched:

+ diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/asyncprof/put_lock_prof.html b/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/asyncprof/put_lock_prof.html new file mode 100644 index 000000000..a1f9fe773 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/asyncprof/put_lock_prof.html @@ -0,0 +1,1046 @@ + + + + + + + +

Lock profile

+
  
+
Produced by async-profiler
+ +
+

+

Matched:

+ diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/report5.md b/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/report5.md new file mode 100644 index 000000000..d34d381c1 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/report5.md @@ -0,0 +1,49 @@ +# Отчёт по 5 стейджу. + +К сожалению, так как 4 стейдж я не делал, сравнений не будет, +так как по сравнению с 3 серьёзные изменения в структуре. + +Также были изменены [скрипты](../scripts) в связи с добавлением +параметров `ack = 2 и from = 3`, а также в скрипты была добавлена +рандомизацией кластера. + +## wrk + +[пример](../report5/wrk/put) +Тестил на 4 тредах и 16 коннекшенах. Точка разладки `12500`, +соответственно тестим на 10000. Стоит отметить стабильную +работу с многопоточкой, и получается заметное улучшение по скорости +относительнно первых стейджей. + +## asyncprof + +### cpu + +[put cpu](../report5/asyncprof/put_cpu_prof.html) +[get cpu](../report5/asyncprof/get_cpu_prof.html) + +Сразу стоит отметить значительное изменение +распределие ресурсов процессора.
+Так `remote` занимает всего около 15% ресурсов процессора, так же как и +обработка таски `completableFeature` и обработка её завершения +в то время как почти вся остальная часть ресурсов уходит на скедулер и пакет +`jdk/internal/net` + +### alloc + +[put alloc](../report5/asyncprof/put_alloc_prof.html) +[get alloc](../report5/asyncprof/get_alloc_prof.html) + +Примерно 30 процентов приходится на всё тот же скедулер, +а аллокации непосредственно обработки запроса (50%) связаны +с хэдерами запросов, примерно 20%. Остальное это аллокации связанные с `CompletableFeature`, +локальными переменными и получением результата. + +### lock + +[put lock](../report5/asyncprof/put_lock_prof.html) +[get lock](../report5/asyncprof/get_lock_prof.html) + +С точки зрения локов картина довольно простая `CompletableFuture` +забирают примерно 80%, что вполне логично. + diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/wrk/get b/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/wrk/get new file mode 100644 index 000000000..04e22b83e --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/wrk/get @@ -0,0 +1,121 @@ +/wrk -d 30 -t 4 -c 16 -R 10000 -L -s /home/sbread/Desktop/labs/HLS/2024-highload-dht/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/get.lua http://localhost:8080 +Running 30s test @ http://localhost:8080 + 4 threads and 16 connections + Thread calibration: mean lat.: 1.413ms, rate sampling interval: 10ms + Thread calibration: mean lat.: 1.369ms, rate sampling interval: 10ms + Thread calibration: mean lat.: 1.405ms, rate sampling interval: 10ms + Thread calibration: mean lat.: 1.378ms, rate sampling interval: 10ms + Thread Stats Avg Stdev Max +/- Stdev + Latency 1.58ms 2.27ms 44.00ms 98.69% + Req/Sec 2.63k 236.75 4.55k 80.29% + Latency Distribution (HdrHistogram - Recorded Latency) + 50.000% 1.32ms + 75.000% 1.77ms + 90.000% 2.21ms + 99.000% 5.20ms + 99.900% 38.49ms + 99.990% 42.56ms + 99.999% 43.55ms +100.000% 44.03ms + + Detailed Percentile spectrum: + Value Percentile TotalCount 1/(1-Percentile) + + 0.194 0.000000 1 1.00 + 0.702 0.100000 19992 1.11 + 0.877 0.200000 39985 1.25 + 1.023 0.300000 60009 1.43 + 1.166 0.400000 80055 1.67 + 1.315 0.500000 99965 2.00 + 1.394 0.550000 109939 2.22 + 1.478 0.600000 119966 2.50 + 1.568 0.650000 129905 2.86 + 1.666 0.700000 139942 3.33 + 1.772 0.750000 149863 4.00 + 1.830 0.775000 154863 4.44 + 1.892 0.800000 159889 5.00 + 1.959 0.825000 164901 5.71 + 2.031 0.850000 169865 6.67 + 2.113 0.875000 174931 8.00 + 2.157 0.887500 177393 8.89 + 2.207 0.900000 179830 10.00 + 2.263 0.912500 182392 11.43 + 2.327 0.925000 184852 13.33 + 2.405 0.937500 187361 16.00 + 2.449 0.943750 188567 17.78 + 2.505 0.950000 189855 20.00 + 2.569 0.956250 191084 22.86 + 2.647 0.962500 192318 26.67 + 2.751 0.968750 193573 32.00 + 2.827 0.971875 194188 35.56 + 2.923 0.975000 194811 40.00 + 3.051 0.978125 195436 45.71 + 3.233 0.981250 196054 53.33 + 3.507 0.984375 196680 64.00 + 3.699 0.985938 196992 71.11 + 3.979 0.987500 197303 80.00 + 4.531 0.989062 197615 91.43 + 5.899 0.990625 197927 106.67 + 7.459 0.992188 198242 128.00 + 8.479 0.992969 198396 142.22 + 11.551 0.993750 198552 160.00 + 15.055 0.994531 198708 182.86 + 18.927 0.995313 198865 213.33 + 22.879 0.996094 199020 256.00 + 24.815 0.996484 199100 284.44 + 26.799 0.996875 199177 320.00 + 28.991 0.997266 199254 365.71 + 31.199 0.997656 199333 426.67 + 33.567 0.998047 199410 512.00 + 34.623 0.998242 199450 568.89 + 35.519 0.998437 199488 640.00 + 36.511 0.998633 199527 731.43 + 37.663 0.998828 199568 853.33 + 38.591 0.999023 199609 1024.00 + 39.135 0.999121 199625 1137.78 + 39.551 0.999219 199644 1280.00 + 40.031 0.999316 199667 1462.86 + 40.287 0.999414 199684 1706.67 + 40.831 0.999512 199703 2048.00 + 41.055 0.999561 199713 2275.56 + 41.215 0.999609 199722 2560.00 + 41.375 0.999658 199734 2925.71 + 41.599 0.999707 199742 3413.33 + 41.983 0.999756 199753 4096.00 + 42.047 0.999780 199757 4551.11 + 42.143 0.999805 199763 5120.00 + 42.207 0.999829 199766 5851.43 + 42.335 0.999854 199771 6826.67 + 42.463 0.999878 199778 8192.00 + 42.559 0.999890 199783 9102.22 + 42.559 0.999902 199783 10240.00 + 42.559 0.999915 199783 11702.86 + 42.623 0.999927 199788 13653.33 + 42.623 0.999939 199788 16384.00 + 42.687 0.999945 199791 18204.44 + 42.687 0.999951 199791 20480.00 + 42.719 0.999957 199793 23405.71 + 42.719 0.999963 199793 27306.67 + 42.751 0.999969 199794 32768.00 + 42.911 0.999973 199795 36408.89 + 42.943 0.999976 199796 40960.00 + 42.943 0.999979 199796 46811.43 + 43.103 0.999982 199797 54613.33 + 43.103 0.999985 199797 65536.00 + 43.551 0.999986 199798 72817.78 + 43.551 0.999988 199798 81920.00 + 43.551 0.999989 199798 93622.86 + 43.903 0.999991 199799 109226.67 + 43.903 0.999992 199799 131072.00 + 43.903 0.999993 199799 145635.56 + 43.903 0.999994 199799 163840.00 + 43.903 0.999995 199799 187245.71 + 44.031 0.999995 199800 218453.33 + 44.031 1.000000 199800 inf +#[Mean = 1.575, StdDeviation = 2.271] +#[Max = 44.000, Total count = 199800] +#[Buckets = 27, SubBuckets = 2048] +---------------------------------------------------------- + 299922 requests in 30.00s, 19.94MB read +Requests/sec: 9997.21 +Transfer/sec: 680.65KB diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/wrk/put b/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/wrk/put new file mode 100644 index 000000000..891aa39a3 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/wrk/put @@ -0,0 +1,117 @@ +./wrk -d 30 -t 4 -c 16 -R 10000 -L -s /home/sbread/Desktop/labs/HLS/2024-highload-dht/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/put.lua http://localhost:8080 +Running 30s test @ http://localhost:8080 + 4 threads and 16 connections + Thread calibration: mean lat.: 6.402ms, rate sampling interval: 10ms + Thread calibration: mean lat.: 6.361ms, rate sampling interval: 10ms + Thread calibration: mean lat.: 6.064ms, rate sampling interval: 10ms + Thread calibration: mean lat.: 6.428ms, rate sampling interval: 10ms + Thread Stats Avg Stdev Max +/- Stdev + Latency 1.64ms 1.73ms 34.72ms 96.25% + Req/Sec 2.64k 236.32 4.55k 70.93% + Latency Distribution (HdrHistogram - Recorded Latency) + 50.000% 1.37ms + 75.000% 1.82ms + 90.000% 2.35ms + 99.000% 8.48ms + 99.900% 24.69ms + 99.990% 30.77ms + 99.999% 34.46ms +100.000% 34.75ms + + Detailed Percentile spectrum: + Value Percentile TotalCount 1/(1-Percentile) + + 0.241 0.000000 1 1.00 + 0.738 0.100000 19989 1.11 + 0.922 0.200000 40056 1.25 + 1.078 0.300000 60083 1.43 + 1.225 0.400000 79931 1.67 + 1.370 0.500000 99947 2.00 + 1.444 0.550000 109936 2.22 + 1.522 0.600000 119880 2.50 + 1.609 0.650000 129875 2.86 + 1.706 0.700000 139928 3.33 + 1.822 0.750000 149932 4.00 + 1.886 0.775000 154904 4.44 + 1.955 0.800000 159860 5.00 + 2.033 0.825000 164829 5.71 + 2.121 0.850000 169833 6.67 + 2.225 0.875000 174869 8.00 + 2.283 0.887500 177328 8.89 + 2.351 0.900000 179833 10.00 + 2.433 0.912500 182350 11.43 + 2.531 0.925000 184803 13.33 + 2.675 0.937500 187315 16.00 + 2.783 0.943750 188571 17.78 + 2.919 0.950000 189798 20.00 + 3.113 0.956250 191048 22.86 + 3.371 0.962500 192302 26.67 + 3.721 0.968750 193550 32.00 + 3.919 0.971875 194173 35.56 + 4.159 0.975000 194797 40.00 + 4.487 0.978125 195419 45.71 + 4.999 0.981250 196044 53.33 + 5.891 0.984375 196665 64.00 + 6.499 0.985938 196977 71.11 + 7.175 0.987500 197289 80.00 + 7.931 0.989062 197601 91.43 + 8.935 0.990625 197916 106.67 + 10.319 0.992188 198227 128.00 + 11.255 0.992969 198382 142.22 + 12.343 0.993750 198538 160.00 + 13.543 0.994531 198695 182.86 + 14.791 0.995313 198850 213.33 + 16.255 0.996094 199008 256.00 + 17.087 0.996484 199084 284.44 + 18.047 0.996875 199164 320.00 + 18.847 0.997266 199241 365.71 + 20.239 0.997656 199319 426.67 + 21.519 0.998047 199396 512.00 + 22.111 0.998242 199436 568.89 + 22.767 0.998437 199476 640.00 + 23.455 0.998633 199514 731.43 + 24.127 0.998828 199552 853.33 + 24.751 0.999023 199591 1024.00 + 24.975 0.999121 199612 1137.78 + 25.199 0.999219 199630 1280.00 + 25.439 0.999316 199650 1462.86 + 25.935 0.999414 199670 1706.67 + 26.207 0.999512 199689 2048.00 + 26.431 0.999561 199699 2275.56 + 26.671 0.999609 199708 2560.00 + 26.927 0.999658 199718 2925.71 + 27.359 0.999707 199729 3413.33 + 27.615 0.999756 199738 4096.00 + 27.919 0.999780 199743 4551.11 + 28.079 0.999805 199747 5120.00 + 28.415 0.999829 199752 5851.43 + 28.703 0.999854 199757 6826.67 + 29.119 0.999878 199762 8192.00 + 30.655 0.999890 199765 9102.22 + 30.863 0.999902 199767 10240.00 + 31.247 0.999915 199769 11702.86 + 31.999 0.999927 199772 13653.33 + 32.399 0.999939 199774 16384.00 + 32.895 0.999945 199776 18204.44 + 33.087 0.999951 199777 20480.00 + 33.407 0.999957 199778 23405.71 + 33.535 0.999963 199779 27306.67 + 33.951 0.999969 199780 32768.00 + 34.175 0.999973 199781 36408.89 + 34.239 0.999976 199782 40960.00 + 34.239 0.999979 199782 46811.43 + 34.271 0.999982 199783 54613.33 + 34.271 0.999985 199783 65536.00 + 34.463 0.999986 199784 72817.78 + 34.463 0.999988 199784 81920.00 + 34.463 0.999989 199784 93622.86 + 34.751 0.999991 199786 109226.67 + 34.751 1.000000 199786 inf +#[Mean = 1.644, StdDeviation = 1.726] +#[Max = 34.720, Total count = 199786] +#[Buckets = 27, SubBuckets = 2048] +---------------------------------------------------------- + 299909 requests in 30.00s, 16.87MB read +Requests/sec: 9997.09 +Transfer/sec: 576.00KB + diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/delete.lua b/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/delete.lua index b9f932bd4..9eddfe7d1 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/delete.lua +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/delete.lua @@ -3,8 +3,8 @@ id = 0 function request() curId = id id = id + 1 - path = "/v0/entity?id=key" .. curId + path = "/v0/entity?id=key" .. curId .. "&ack=2&from=3" headers = {} - headers["Host"] = "localhost:8080" + headers["Host"] = "localhost:808" .. string.char(math.random(1, 4)) return wrk.format("DELETE", path, headers) end diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/get.lua b/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/get.lua index 3ed630fda..297c85668 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/get.lua +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/get.lua @@ -3,8 +3,8 @@ id = 0 function request() curId = id id = id + 1 - path = "/v0/entity?id=key" .. curId + path = "/v0/entity?id=key" .. curId .. "&ack=2&from=3" headers = {} - headers["Host"] = "localhost:8080" + headers["Host"] = "localhost:808" .. string.char(math.random(1, 4)) return wrk.format("GET", path, headers) end diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/put.lua b/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/put.lua index f87fed66c..03d96ab41 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/put.lua +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/put.lua @@ -3,9 +3,9 @@ id = 0 function request() curId = id id = id + 1 - path = "/v0/entity?id=key" .. curId + path = "/v0/entity?id=key" .. curId .. "&ack=2&from=3" headers = {} - headers["Host"] = "localhost:8080" + headers["Host"] = "localhost:808" .. string.char(math.random(1, 4)) value = "value" .. curId return wrk.format("PUT", path, headers, value) end From dba18b94c666cfa18c2907e63047ec26ce9eff9f Mon Sep 17 00:00:00 2001 From: sbread Date: Wed, 15 May 2024 20:33:59 +0300 Subject: [PATCH 21/23] upd rep, part 1 --- .../test/osipovdaniil/MergeHandleResult.java | 2 +- .../vk/itmo/test/osipovdaniil/ServerImpl.java | 17 +- .../itmo/test/osipovdaniil/report5/report5.md | 13 + .../itmo/test/osipovdaniil/report5/wrk/3_xx | 0 .../itmo/test/osipovdaniil/report5/wrk/5_4xx | 245 ++++++++++++++++++ .../itmo/test/osipovdaniil/scripts/delete.lua | 4 +- .../vk/itmo/test/osipovdaniil/scripts/get.lua | 4 +- .../vk/itmo/test/osipovdaniil/scripts/put.lua | 4 +- 8 files changed, 275 insertions(+), 14 deletions(-) create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/report5/wrk/3_xx create mode 100644 src/main/java/ru/vk/itmo/test/osipovdaniil/report5/wrk/5_4xx diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/MergeHandleResult.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/MergeHandleResult.java index 6482076e1..a258e3ee4 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/MergeHandleResult.java +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/MergeHandleResult.java @@ -29,7 +29,7 @@ public MergeHandleResult(HttpSession session, int size, int ack) { public boolean add(int index, HandleResult handleResult) { handleResults[index] = handleResult; int valid = validateResultStatus(handleResult.status()) ? countValid.getAndIncrement() : countValid.get(); - if (valid >= ack) { + if (valid == ack) { sendResult(); return true; } diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java b/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java index 4e26ddc9d..81a8bdb94 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/ServerImpl.java @@ -34,12 +34,14 @@ public class ServerImpl extends HttpServer { + public static final int EXECUTOR_SERVICE_TERMINATION_TIMEOUT = 60; private static final String HEADER_REMOTE = "X-flag-remote-server-to-node"; private static final String HEADER_REMOTE_ONE_NIO_HEADER = HEADER_REMOTE + ": true"; private static final String HEADER_TIMESTAMP = "X-flag-remote-server-to-node"; private static final String HEADER_TIMESTAMP_ONE_NIO_HEADER = HEADER_TIMESTAMP + ": "; private static final Logger log = LoggerFactory.getLogger(ServerImpl.class); private static final int THREADS = Runtime.getRuntime().availableProcessors(); + private static final long REMOTE_HEADER_TIMEOUT = 500; private final ExecutorService executorLocal = Executors.newFixedThreadPool(THREADS / 2, new CustomThreadFactory("local-work")); @@ -211,7 +213,7 @@ private HandleResult invokeRemote(final String executorNode, final Request reque : HttpRequest.BodyPublishers.ofByteArray(request.getBody()) ) .header(HEADER_REMOTE, "true") - .timeout(Duration.ofMillis(500)) + .timeout(Duration.ofMillis(REMOTE_HEADER_TIMEOUT)) .build(); final HttpResponse httpResponse = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofByteArray()); final Optional string = httpResponse.headers().firstValue(HEADER_TIMESTAMP); @@ -273,15 +275,15 @@ private int[] getIndexes(final String id, final int count) { int[] maxHashs = new int[count]; for (int i = 0; i < count; i++) { - String url = config.clusterUrls().get(i); - int hash = Hash.murmur3(url + id); + final String url = config.clusterUrls().get(i); + final int hash = Hash.murmur3(url + id); result[i] = i; maxHashs[i] = hash; } for (int i = count; i < config.clusterUrls().size(); i++) { - String url = config.clusterUrls().get(i); - int hash = Hash.murmur3(url + id); + final String url = config.clusterUrls().get(i); + final int hash = Hash.murmur3(url + id); for (int j = 0; j < maxHashs.length; j++) { int maxHash = maxHashs[j]; if (maxHash < hash) { @@ -300,11 +302,12 @@ private interface ERunnable { private void shutdownAndAwaitTermination(ExecutorService pool) { try { - if (!pool.awaitTermination(60, TimeUnit.MILLISECONDS)) { + if (!pool.awaitTermination(EXECUTOR_SERVICE_TERMINATION_TIMEOUT, TimeUnit.MILLISECONDS)) { pool.shutdownNow(); - if (!pool.awaitTermination(60, TimeUnit.MILLISECONDS)) { + if (!pool.awaitTermination(EXECUTOR_SERVICE_TERMINATION_TIMEOUT, TimeUnit.MILLISECONDS)) { log.info("Pool did not terminate"); } + } } catch (InterruptedException ie) { pool.shutdownNow(); diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/report5.md b/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/report5.md index d34d381c1..2c1c2443d 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/report5.md +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/report5.md @@ -47,3 +47,16 @@ С точки зрения локов картина довольно простая `CompletableFuture` забирают примерно 80%, что вполне логично. +## Сравнение с 3 стейджем + +Предлагается отключить 1 шард и посмотреть на количество ответов не 2xx, 3xx + +Для этого в скриптах хосты будут 8080, 8090, 8900. Параметры `ack и from` убираем, +то есть в случае 5 стейджа бужут выставляться дефолтные значения. +А зараним только 8080, 8090. + +[5 стейдж](../report5/wrk/5_4xx) + +Стоит заметить что в обоих тестах цифры сходятся, так в первом случае +`59582 / 239994 = 0.2483`, а во втором `73821 / 296738 = 0.2488`. +Итого примерно `1/4` неудачных запросов. diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/wrk/3_xx b/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/wrk/3_xx new file mode 100644 index 000000000..e69de29bb diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/wrk/5_4xx b/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/wrk/5_4xx new file mode 100644 index 000000000..999d13dc2 --- /dev/null +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/wrk/5_4xx @@ -0,0 +1,245 @@ +./wrk -d 30 -t 4 -c 4 -R 8000 -L -s /home/sbread/Desktop/labs/HLS/2024-highload-dht/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/put.lua http://localhost:8080 +Running 30s test @ http://localhost:8080 + 4 threads and 4 connections + Thread calibration: mean lat.: 1.219ms, rate sampling interval: 10ms + Thread calibration: mean lat.: 1.224ms, rate sampling interval: 10ms + Thread calibration: mean lat.: 1.250ms, rate sampling interval: 10ms + Thread calibration: mean lat.: 1.235ms, rate sampling interval: 10ms + Thread Stats Avg Stdev Max +/- Stdev + Latency 1.31ms 1.96ms 26.53ms 97.48% + Req/Sec 2.11k 232.10 4.11k 84.49% + Latency Distribution (HdrHistogram - Recorded Latency) + 50.000% 1.05ms + 75.000% 1.39ms + 90.000% 1.85ms + 99.000% 12.96ms + 99.900% 22.33ms + 99.990% 24.67ms + 99.999% 26.19ms +100.000% 26.54ms + + Detailed Percentile spectrum: + Value Percentile TotalCount 1/(1-Percentile) + + 0.065 0.000000 1 1.00 + 0.411 0.100000 16011 1.11 + 0.593 0.200000 32046 1.25 + 0.760 0.300000 47991 1.43 + 0.912 0.400000 64068 1.67 + 1.049 0.500000 80033 2.00 + 1.109 0.550000 88062 2.22 + 1.167 0.600000 96100 2.50 + 1.229 0.650000 104015 2.86 + 1.296 0.700000 111991 3.33 + 1.389 0.750000 119970 4.00 + 1.454 0.775000 124002 4.44 + 1.525 0.800000 127998 5.00 + 1.599 0.825000 131966 5.71 + 1.675 0.850000 136003 6.67 + 1.757 0.875000 140006 8.00 + 1.800 0.887500 142001 8.89 + 1.845 0.900000 143979 10.00 + 1.892 0.912500 145979 11.43 + 1.944 0.925000 147975 13.33 + 2.001 0.937500 149964 16.00 + 2.034 0.943750 150987 17.78 + 2.067 0.950000 151970 20.00 + 2.105 0.956250 152969 22.86 + 2.167 0.962500 153968 26.67 + 2.501 0.968750 154959 32.00 + 2.865 0.971875 155459 35.56 + 3.319 0.975000 155960 40.00 + 4.039 0.978125 156458 45.71 + 5.755 0.981250 156958 53.33 + 8.103 0.984375 157459 64.00 + 9.263 0.985938 157708 71.11 + 10.711 0.987500 157958 80.00 + 12.159 0.989062 158208 91.43 + 13.399 0.990625 158459 106.67 + 14.711 0.992188 158708 128.00 + 15.223 0.992969 158837 142.22 + 16.199 0.993750 158958 160.00 + 17.407 0.994531 159084 182.86 + 18.575 0.995313 159209 213.33 + 19.711 0.996094 159333 256.00 + 19.967 0.996484 159395 284.44 + 20.255 0.996875 159460 320.00 + 20.543 0.997266 159520 365.71 + 20.959 0.997656 159583 426.67 + 21.343 0.998047 159646 512.00 + 21.519 0.998242 159676 568.89 + 21.679 0.998437 159708 640.00 + 21.871 0.998633 159742 731.43 + 22.079 0.998828 159770 853.33 + 22.335 0.999023 159801 1024.00 + 22.479 0.999121 159818 1137.78 + 22.687 0.999219 159833 1280.00 + 22.911 0.999316 159848 1462.86 + 23.215 0.999414 159864 1706.67 + 23.423 0.999512 159879 2048.00 + 23.567 0.999561 159887 2275.56 + 23.631 0.999609 159896 2560.00 + 23.695 0.999658 159903 2925.71 + 23.855 0.999707 159912 3413.33 + 23.887 0.999756 159918 4096.00 + 23.999 0.999780 159923 4551.11 + 24.047 0.999805 159926 5120.00 + 24.111 0.999829 159930 5851.43 + 24.223 0.999854 159934 6826.67 + 24.383 0.999878 159938 8192.00 + 24.527 0.999890 159940 9102.22 + 24.799 0.999902 159942 10240.00 + 24.879 0.999915 159944 11702.86 + 25.263 0.999927 159946 13653.33 + 25.535 0.999939 159948 16384.00 + 25.599 0.999945 159949 18204.44 + 25.775 0.999951 159950 20480.00 + 25.871 0.999957 159951 23405.71 + 25.903 0.999963 159952 27306.67 + 26.095 0.999969 159953 32768.00 + 26.095 0.999973 159953 36408.89 + 26.143 0.999976 159954 40960.00 + 26.143 0.999979 159954 46811.43 + 26.191 0.999982 159955 54613.33 + 26.191 0.999985 159955 65536.00 + 26.191 0.999986 159955 72817.78 + 26.447 0.999988 159956 81920.00 + 26.447 0.999989 159956 93622.86 + 26.447 0.999991 159956 109226.67 + 26.447 0.999992 159956 131072.00 + 26.447 0.999993 159956 145635.56 + 26.543 0.999994 159957 163840.00 + 26.543 1.000000 159957 inf +#[Mean = 1.315, StdDeviation = 1.965] +#[Max = 26.528, Total count = 159957] +#[Buckets = 27, SubBuckets = 2048] +---------------------------------------------------------- + 239994 requests in 30.00s, 14.81MB read + Non-2xx or 3xx responses: 59582 +Requests/sec: 7999.83 +Transfer/sec: 505.54KB + +------------------------------------------------------- + +./wrk -d 30 -t 4 -c 4 -R 10000 -L -s /home/sbread/Desktop/labs/HLS/2024-highload-dht/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/put.lua http://localhost:8080 +Running 30s test @ http://localhost:8080 + 4 threads and 4 connections + Thread calibration: mean lat.: 1.798ms, rate sampling interval: 10ms + Thread calibration: mean lat.: 1.747ms, rate sampling interval: 10ms + Thread calibration: mean lat.: 1.776ms, rate sampling interval: 10ms + Thread calibration: mean lat.: 1.615ms, rate sampling interval: 10ms + Thread Stats Avg Stdev Max +/- Stdev + Latency 2.89ms 15.59ms 325.89ms 97.59% + Req/Sec 2.60k 415.26 4.33k 89.41% + Latency Distribution (HdrHistogram - Recorded Latency) + 50.000% 0.93ms + 75.000% 1.26ms + 90.000% 2.29ms + 99.000% 36.80ms + 99.900% 284.16ms + 99.990% 319.49ms + 99.999% 325.38ms +100.000% 326.14ms + + Detailed Percentile spectrum: + Value Percentile TotalCount 1/(1-Percentile) + + 0.068 0.000000 2 1.00 + 0.370 0.100000 19738 1.11 + 0.517 0.200000 39421 1.25 + 0.656 0.300000 59156 1.43 + 0.792 0.400000 78752 1.67 + 0.927 0.500000 98359 2.00 + 0.993 0.550000 108312 2.22 + 1.057 0.600000 118113 2.50 + 1.120 0.650000 127863 2.86 + 1.185 0.700000 137765 3.33 + 1.259 0.750000 147646 4.00 + 1.298 0.775000 152510 4.44 + 1.347 0.800000 157406 5.00 + 1.450 0.825000 162304 5.71 + 1.639 0.850000 167203 6.67 + 1.897 0.875000 172118 8.00 + 2.051 0.887500 174591 8.89 + 2.287 0.900000 177047 10.00 + 2.763 0.912500 179490 11.43 + 3.367 0.925000 181951 13.33 + 4.399 0.937500 184415 16.00 + 5.159 0.943750 185638 17.78 + 6.267 0.950000 186868 20.00 + 7.803 0.956250 188097 22.86 + 9.935 0.962500 189325 26.67 + 12.687 0.968750 190556 32.00 + 14.367 0.971875 191170 35.56 + 17.167 0.975000 191784 40.00 + 25.439 0.978125 192400 45.71 + 28.719 0.981250 193016 53.33 + 30.783 0.984375 193633 64.00 + 31.999 0.985938 193936 71.11 + 34.271 0.987500 194244 80.00 + 35.999 0.989062 194554 91.43 + 37.919 0.990625 194859 106.67 + 42.271 0.992188 195165 128.00 + 46.335 0.992969 195319 142.22 + 56.255 0.993750 195472 160.00 + 60.799 0.994531 195629 182.86 + 71.935 0.995313 195779 213.33 + 131.967 0.996094 195933 256.00 + 143.231 0.996484 196013 284.44 + 173.311 0.996875 196087 320.00 + 191.871 0.997266 196164 365.71 + 201.215 0.997656 196242 426.67 + 210.687 0.998047 196317 512.00 + 218.495 0.998242 196356 568.89 + 232.959 0.998437 196394 640.00 + 255.615 0.998633 196433 731.43 + 272.895 0.998828 196471 853.33 + 284.927 0.999023 196509 1024.00 + 289.279 0.999121 196529 1137.78 + 294.911 0.999219 196548 1280.00 + 298.751 0.999316 196569 1462.86 + 300.799 0.999414 196587 1706.67 + 304.639 0.999512 196606 2048.00 + 306.175 0.999561 196616 2275.56 + 309.247 0.999609 196625 2560.00 + 310.015 0.999658 196635 2925.71 + 311.295 0.999707 196644 3413.33 + 312.575 0.999756 196653 4096.00 + 314.111 0.999780 196658 4551.11 + 314.623 0.999805 196663 5120.00 + 315.903 0.999829 196670 5851.43 + 317.951 0.999854 196674 6826.67 + 318.719 0.999878 196677 8192.00 + 319.487 0.999890 196682 9102.22 + 319.487 0.999902 196682 10240.00 + 320.255 0.999915 196685 11702.86 + 320.767 0.999927 196687 13653.33 + 323.071 0.999939 196689 16384.00 + 324.351 0.999945 196691 18204.44 + 324.607 0.999951 196693 20480.00 + 324.607 0.999957 196693 23405.71 + 324.863 0.999963 196694 27306.67 + 325.375 0.999969 196700 32768.00 + 325.375 0.999973 196700 36408.89 + 325.375 0.999976 196700 40960.00 + 325.375 0.999979 196700 46811.43 + 325.375 0.999982 196700 54613.33 + 325.375 0.999985 196700 65536.00 + 325.375 0.999986 196700 72817.78 + 325.375 0.999988 196700 81920.00 + 325.375 0.999989 196700 93622.86 + 325.375 0.999991 196700 109226.67 + 325.375 0.999992 196700 131072.00 + 325.375 0.999993 196700 145635.56 + 325.375 0.999994 196700 163840.00 + 325.375 0.999995 196700 187245.71 + 326.143 0.999995 196701 218453.33 + 326.143 1.000000 196701 inf +#[Mean = 2.892, StdDeviation = 15.589] +#[Max = 325.888, Total count = 196701] +#[Buckets = 27, SubBuckets = 2048] +---------------------------------------------------------- + 296738 requests in 30.00s, 18.32MB read + Non-2xx or 3xx responses: 73821 +Requests/sec: 9891.39 +Transfer/sec: 625.18KB diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/delete.lua b/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/delete.lua index 9eddfe7d1..e354828e7 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/delete.lua +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/delete.lua @@ -3,8 +3,8 @@ id = 0 function request() curId = id id = id + 1 - path = "/v0/entity?id=key" .. curId .. "&ack=2&from=3" + path = "/v0/entity?id=key" .. curId headers = {} - headers["Host"] = "localhost:808" .. string.char(math.random(1, 4)) + headers["Host"] = "localhost:808" .. string.char((math.random(1, 4) - 1) * 10) return wrk.format("DELETE", path, headers) end diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/get.lua b/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/get.lua index 297c85668..daca6dc47 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/get.lua +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/get.lua @@ -3,8 +3,8 @@ id = 0 function request() curId = id id = id + 1 - path = "/v0/entity?id=key" .. curId .. "&ack=2&from=3" + path = "/v0/entity?id=key" .. curId headers = {} - headers["Host"] = "localhost:808" .. string.char(math.random(1, 4)) + headers["Host"] = "localhost:808" .. string.char((math.random(1, 4) - 1) * 10) return wrk.format("GET", path, headers) end diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/put.lua b/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/put.lua index 03d96ab41..ea90d2bd8 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/put.lua +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/put.lua @@ -3,9 +3,9 @@ id = 0 function request() curId = id id = id + 1 - path = "/v0/entity?id=key" .. curId .. "&ack=2&from=3" + path = "/v0/entity?id=key" .. curId headers = {} - headers["Host"] = "localhost:808" .. string.char(math.random(1, 4)) + headers["Host"] = "localhost:808" .. string.char((math.random(1, 4) - 1) * 10) value = "value" .. curId return wrk.format("PUT", path, headers, value) end From 40664f49728f3eb60bec35dfaaa202d7e7e1cbad Mon Sep 17 00:00:00 2001 From: sbread Date: Wed, 15 May 2024 21:08:05 +0300 Subject: [PATCH 22/23] upd rep, part 1 v2 --- .../itmo/test/osipovdaniil/report5/report5.md | 6 +- .../osipovdaniil/report5/wrk/{3_xx => 3_4xx} | 0 .../itmo/test/osipovdaniil/report5/wrk/5_4xx | 319 +++++------------- 3 files changed, 88 insertions(+), 237 deletions(-) rename src/main/java/ru/vk/itmo/test/osipovdaniil/report5/wrk/{3_xx => 3_4xx} (100%) diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/report5.md b/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/report5.md index 2c1c2443d..0cc166dfc 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/report5.md +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/report5.md @@ -56,7 +56,7 @@ А зараним только 8080, 8090. [5 стейдж](../report5/wrk/5_4xx) +[3 стейдж](../report5/wrk/3_4xx) -Стоит заметить что в обоих тестах цифры сходятся, так в первом случае -`59582 / 239994 = 0.2483`, а во втором `73821 / 296738 = 0.2488`. -Итого примерно `1/4` неудачных запросов. +В случае 5 стейджа +`18733 / 76301 = 0.2455`, а в случае 3 стейджа. diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/wrk/3_xx b/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/wrk/3_4xx similarity index 100% rename from src/main/java/ru/vk/itmo/test/osipovdaniil/report5/wrk/3_xx rename to src/main/java/ru/vk/itmo/test/osipovdaniil/report5/wrk/3_4xx diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/wrk/5_4xx b/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/wrk/5_4xx index 999d13dc2..f1c463a69 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/wrk/5_4xx +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/wrk/5_4xx @@ -1,245 +1,96 @@ -./wrk -d 30 -t 4 -c 4 -R 8000 -L -s /home/sbread/Desktop/labs/HLS/2024-highload-dht/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/put.lua http://localhost:8080 -Running 30s test @ http://localhost:8080 - 4 threads and 4 connections - Thread calibration: mean lat.: 1.219ms, rate sampling interval: 10ms - Thread calibration: mean lat.: 1.224ms, rate sampling interval: 10ms - Thread calibration: mean lat.: 1.250ms, rate sampling interval: 10ms - Thread calibration: mean lat.: 1.235ms, rate sampling interval: 10ms - Thread Stats Avg Stdev Max +/- Stdev - Latency 1.31ms 1.96ms 26.53ms 97.48% - Req/Sec 2.11k 232.10 4.11k 84.49% - Latency Distribution (HdrHistogram - Recorded Latency) - 50.000% 1.05ms - 75.000% 1.39ms - 90.000% 1.85ms - 99.000% 12.96ms - 99.900% 22.33ms - 99.990% 24.67ms - 99.999% 26.19ms -100.000% 26.54ms - - Detailed Percentile spectrum: - Value Percentile TotalCount 1/(1-Percentile) - - 0.065 0.000000 1 1.00 - 0.411 0.100000 16011 1.11 - 0.593 0.200000 32046 1.25 - 0.760 0.300000 47991 1.43 - 0.912 0.400000 64068 1.67 - 1.049 0.500000 80033 2.00 - 1.109 0.550000 88062 2.22 - 1.167 0.600000 96100 2.50 - 1.229 0.650000 104015 2.86 - 1.296 0.700000 111991 3.33 - 1.389 0.750000 119970 4.00 - 1.454 0.775000 124002 4.44 - 1.525 0.800000 127998 5.00 - 1.599 0.825000 131966 5.71 - 1.675 0.850000 136003 6.67 - 1.757 0.875000 140006 8.00 - 1.800 0.887500 142001 8.89 - 1.845 0.900000 143979 10.00 - 1.892 0.912500 145979 11.43 - 1.944 0.925000 147975 13.33 - 2.001 0.937500 149964 16.00 - 2.034 0.943750 150987 17.78 - 2.067 0.950000 151970 20.00 - 2.105 0.956250 152969 22.86 - 2.167 0.962500 153968 26.67 - 2.501 0.968750 154959 32.00 - 2.865 0.971875 155459 35.56 - 3.319 0.975000 155960 40.00 - 4.039 0.978125 156458 45.71 - 5.755 0.981250 156958 53.33 - 8.103 0.984375 157459 64.00 - 9.263 0.985938 157708 71.11 - 10.711 0.987500 157958 80.00 - 12.159 0.989062 158208 91.43 - 13.399 0.990625 158459 106.67 - 14.711 0.992188 158708 128.00 - 15.223 0.992969 158837 142.22 - 16.199 0.993750 158958 160.00 - 17.407 0.994531 159084 182.86 - 18.575 0.995313 159209 213.33 - 19.711 0.996094 159333 256.00 - 19.967 0.996484 159395 284.44 - 20.255 0.996875 159460 320.00 - 20.543 0.997266 159520 365.71 - 20.959 0.997656 159583 426.67 - 21.343 0.998047 159646 512.00 - 21.519 0.998242 159676 568.89 - 21.679 0.998437 159708 640.00 - 21.871 0.998633 159742 731.43 - 22.079 0.998828 159770 853.33 - 22.335 0.999023 159801 1024.00 - 22.479 0.999121 159818 1137.78 - 22.687 0.999219 159833 1280.00 - 22.911 0.999316 159848 1462.86 - 23.215 0.999414 159864 1706.67 - 23.423 0.999512 159879 2048.00 - 23.567 0.999561 159887 2275.56 - 23.631 0.999609 159896 2560.00 - 23.695 0.999658 159903 2925.71 - 23.855 0.999707 159912 3413.33 - 23.887 0.999756 159918 4096.00 - 23.999 0.999780 159923 4551.11 - 24.047 0.999805 159926 5120.00 - 24.111 0.999829 159930 5851.43 - 24.223 0.999854 159934 6826.67 - 24.383 0.999878 159938 8192.00 - 24.527 0.999890 159940 9102.22 - 24.799 0.999902 159942 10240.00 - 24.879 0.999915 159944 11702.86 - 25.263 0.999927 159946 13653.33 - 25.535 0.999939 159948 16384.00 - 25.599 0.999945 159949 18204.44 - 25.775 0.999951 159950 20480.00 - 25.871 0.999957 159951 23405.71 - 25.903 0.999963 159952 27306.67 - 26.095 0.999969 159953 32768.00 - 26.095 0.999973 159953 36408.89 - 26.143 0.999976 159954 40960.00 - 26.143 0.999979 159954 46811.43 - 26.191 0.999982 159955 54613.33 - 26.191 0.999985 159955 65536.00 - 26.191 0.999986 159955 72817.78 - 26.447 0.999988 159956 81920.00 - 26.447 0.999989 159956 93622.86 - 26.447 0.999991 159956 109226.67 - 26.447 0.999992 159956 131072.00 - 26.447 0.999993 159956 145635.56 - 26.543 0.999994 159957 163840.00 - 26.543 1.000000 159957 inf -#[Mean = 1.315, StdDeviation = 1.965] -#[Max = 26.528, Total count = 159957] -#[Buckets = 27, SubBuckets = 2048] ----------------------------------------------------------- - 239994 requests in 30.00s, 14.81MB read - Non-2xx or 3xx responses: 59582 -Requests/sec: 7999.83 -Transfer/sec: 505.54KB - -------------------------------------------------------- - ./wrk -d 30 -t 4 -c 4 -R 10000 -L -s /home/sbread/Desktop/labs/HLS/2024-highload-dht/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/put.lua http://localhost:8080 Running 30s test @ http://localhost:8080 4 threads and 4 connections - Thread calibration: mean lat.: 1.798ms, rate sampling interval: 10ms - Thread calibration: mean lat.: 1.747ms, rate sampling interval: 10ms - Thread calibration: mean lat.: 1.776ms, rate sampling interval: 10ms - Thread calibration: mean lat.: 1.615ms, rate sampling interval: 10ms + Thread calibration: mean lat.: 4902.109ms, rate sampling interval: 14852ms + Thread calibration: mean lat.: 4880.748ms, rate sampling interval: 14835ms + Thread calibration: mean lat.: 4878.872ms, rate sampling interval: 14827ms + Thread calibration: mean lat.: 4896.315ms, rate sampling interval: 14835ms Thread Stats Avg Stdev Max +/- Stdev - Latency 2.89ms 15.59ms 325.89ms 97.59% - Req/Sec 2.60k 415.26 4.33k 89.41% + Latency 15.09s 4.14s 22.38s 58.09% + Req/Sec 696.50 2.06 698.00 75.00% Latency Distribution (HdrHistogram - Recorded Latency) - 50.000% 0.93ms - 75.000% 1.26ms - 90.000% 2.29ms - 99.000% 36.80ms - 99.900% 284.16ms - 99.990% 319.49ms - 99.999% 325.38ms -100.000% 326.14ms + 50.000% 15.08s + 75.000% 18.66s + 90.000% 20.79s + 99.000% 22.13s + 99.900% 22.36s + 99.990% 22.40s + 99.999% 22.40s +100.000% 22.40s Detailed Percentile spectrum: Value Percentile TotalCount 1/(1-Percentile) - 0.068 0.000000 2 1.00 - 0.370 0.100000 19738 1.11 - 0.517 0.200000 39421 1.25 - 0.656 0.300000 59156 1.43 - 0.792 0.400000 78752 1.67 - 0.927 0.500000 98359 2.00 - 0.993 0.550000 108312 2.22 - 1.057 0.600000 118113 2.50 - 1.120 0.650000 127863 2.86 - 1.185 0.700000 137765 3.33 - 1.259 0.750000 147646 4.00 - 1.298 0.775000 152510 4.44 - 1.347 0.800000 157406 5.00 - 1.450 0.825000 162304 5.71 - 1.639 0.850000 167203 6.67 - 1.897 0.875000 172118 8.00 - 2.051 0.887500 174591 8.89 - 2.287 0.900000 177047 10.00 - 2.763 0.912500 179490 11.43 - 3.367 0.925000 181951 13.33 - 4.399 0.937500 184415 16.00 - 5.159 0.943750 185638 17.78 - 6.267 0.950000 186868 20.00 - 7.803 0.956250 188097 22.86 - 9.935 0.962500 189325 26.67 - 12.687 0.968750 190556 32.00 - 14.367 0.971875 191170 35.56 - 17.167 0.975000 191784 40.00 - 25.439 0.978125 192400 45.71 - 28.719 0.981250 193016 53.33 - 30.783 0.984375 193633 64.00 - 31.999 0.985938 193936 71.11 - 34.271 0.987500 194244 80.00 - 35.999 0.989062 194554 91.43 - 37.919 0.990625 194859 106.67 - 42.271 0.992188 195165 128.00 - 46.335 0.992969 195319 142.22 - 56.255 0.993750 195472 160.00 - 60.799 0.994531 195629 182.86 - 71.935 0.995313 195779 213.33 - 131.967 0.996094 195933 256.00 - 143.231 0.996484 196013 284.44 - 173.311 0.996875 196087 320.00 - 191.871 0.997266 196164 365.71 - 201.215 0.997656 196242 426.67 - 210.687 0.998047 196317 512.00 - 218.495 0.998242 196356 568.89 - 232.959 0.998437 196394 640.00 - 255.615 0.998633 196433 731.43 - 272.895 0.998828 196471 853.33 - 284.927 0.999023 196509 1024.00 - 289.279 0.999121 196529 1137.78 - 294.911 0.999219 196548 1280.00 - 298.751 0.999316 196569 1462.86 - 300.799 0.999414 196587 1706.67 - 304.639 0.999512 196606 2048.00 - 306.175 0.999561 196616 2275.56 - 309.247 0.999609 196625 2560.00 - 310.015 0.999658 196635 2925.71 - 311.295 0.999707 196644 3413.33 - 312.575 0.999756 196653 4096.00 - 314.111 0.999780 196658 4551.11 - 314.623 0.999805 196663 5120.00 - 315.903 0.999829 196670 5851.43 - 317.951 0.999854 196674 6826.67 - 318.719 0.999878 196677 8192.00 - 319.487 0.999890 196682 9102.22 - 319.487 0.999902 196682 10240.00 - 320.255 0.999915 196685 11702.86 - 320.767 0.999927 196687 13653.33 - 323.071 0.999939 196689 16384.00 - 324.351 0.999945 196691 18204.44 - 324.607 0.999951 196693 20480.00 - 324.607 0.999957 196693 23405.71 - 324.863 0.999963 196694 27306.67 - 325.375 0.999969 196700 32768.00 - 325.375 0.999973 196700 36408.89 - 325.375 0.999976 196700 40960.00 - 325.375 0.999979 196700 46811.43 - 325.375 0.999982 196700 54613.33 - 325.375 0.999985 196700 65536.00 - 325.375 0.999986 196700 72817.78 - 325.375 0.999988 196700 81920.00 - 325.375 0.999989 196700 93622.86 - 325.375 0.999991 196700 109226.67 - 325.375 0.999992 196700 131072.00 - 325.375 0.999993 196700 145635.56 - 325.375 0.999994 196700 163840.00 - 325.375 0.999995 196700 187245.71 - 326.143 0.999995 196701 218453.33 - 326.143 1.000000 196701 inf -#[Mean = 2.892, StdDeviation = 15.589] -#[Max = 325.888, Total count = 196701] + 7905.279 0.000000 7 1.00 + 9388.031 0.100000 5548 1.11 + 10821.631 0.200000 11092 1.25 + 12214.271 0.300000 16630 1.43 + 13656.063 0.400000 22163 1.67 + 15081.471 0.500000 27696 2.00 + 15884.287 0.550000 30450 2.22 + 16564.223 0.600000 33223 2.50 + 17285.119 0.650000 36032 2.86 + 17940.479 0.700000 38758 3.33 + 18661.375 0.750000 41574 4.00 + 19005.439 0.775000 42962 4.44 + 19365.887 0.800000 44306 5.00 + 19775.487 0.825000 45683 5.71 + 20119.551 0.850000 47127 6.67 + 20447.231 0.875000 48466 8.00 + 20611.071 0.887500 49208 8.89 + 20791.295 0.900000 49851 10.00 + 20987.903 0.912500 50513 11.43 + 21217.279 0.925000 51241 13.33 + 21413.887 0.937500 51943 16.00 + 21495.807 0.943750 52244 17.78 + 21594.111 0.950000 52612 20.00 + 21676.031 0.956250 52960 22.86 + 21790.719 0.962500 53343 26.67 + 21872.639 0.968750 53689 32.00 + 21905.407 0.971875 53832 35.56 + 21954.559 0.975000 54039 40.00 + 21987.327 0.978125 54181 45.71 + 22020.095 0.981250 54329 53.33 + 22069.247 0.984375 54542 64.00 + 22085.631 0.985938 54609 71.11 + 22102.015 0.987500 54687 80.00 + 22134.783 0.989062 54818 91.43 + 22151.167 0.990625 54886 106.67 + 22167.551 0.992188 54955 128.00 + 22183.935 0.992969 54999 142.22 + 22200.319 0.993750 55022 160.00 + 22233.087 0.994531 55078 182.86 + 22265.855 0.995313 55101 213.33 + 22315.007 0.996094 55161 256.00 + 22331.391 0.996484 55218 284.44 + 22331.391 0.996875 55218 320.00 + 22331.391 0.997266 55218 365.71 + 22347.775 0.997656 55276 426.67 + 22347.775 0.998047 55276 512.00 + 22347.775 0.998242 55276 568.89 + 22347.775 0.998437 55276 640.00 + 22364.159 0.998633 55319 731.43 + 22364.159 0.998828 55319 853.33 + 22364.159 0.999023 55319 1024.00 + 22364.159 0.999121 55319 1137.78 + 22364.159 0.999219 55319 1280.00 + 22364.159 0.999316 55319 1462.86 + 22380.543 0.999414 55346 1706.67 + 22380.543 0.999512 55346 2048.00 + 22380.543 0.999561 55346 2275.56 + 22380.543 0.999609 55346 2560.00 + 22380.543 0.999658 55346 2925.71 + 22380.543 0.999707 55346 3413.33 + 22380.543 0.999756 55346 4096.00 + 22380.543 0.999780 55346 4551.11 + 22380.543 0.999805 55346 5120.00 + 22396.927 0.999829 55356 5851.43 + 22396.927 1.000000 55356 inf +#[Mean = 15093.395, StdDeviation = 4137.094] +#[Max = 22380.544, Total count = 55356] #[Buckets = 27, SubBuckets = 2048] ---------------------------------------------------------- - 296738 requests in 30.00s, 18.32MB read - Non-2xx or 3xx responses: 73821 -Requests/sec: 9891.39 -Transfer/sec: 625.18KB + 76301 requests in 30.00s, 4.70MB read + Non-2xx or 3xx responses: 18733 +Requests/sec: 2543.33 +Transfer/sec: 160.56KB From e3b930ba6ea22b5894f318332cdbc16ebf62da72 Mon Sep 17 00:00:00 2001 From: sbread Date: Wed, 15 May 2024 21:16:52 +0300 Subject: [PATCH 23/23] upd rep, part 2 --- .../itmo/test/osipovdaniil/report5/report5.md | 8 +- .../itmo/test/osipovdaniil/report5/wrk/3_4xx | 114 ++++++++++++++++++ 2 files changed, 121 insertions(+), 1 deletion(-) diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/report5.md b/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/report5.md index 0cc166dfc..40c8d1a5e 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/report5.md +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/report5.md @@ -59,4 +59,10 @@ [3 стейдж](../report5/wrk/3_4xx) В случае 5 стейджа -`18733 / 76301 = 0.2455`, а в случае 3 стейджа. +`18733 / 76301 = 0.2455`, а в случае 3 стейджа `70059 / 149816 = 0.4677`. + +Да в 5 стейдже цифры задержки плохие (экспешены вылетали по другому при тестировании), +но это не отменяет логичного и закономерного факта (так как соотношение остаётся). Соотношение плохих ответов +ко всем запросам в 5 стейдже лучше. Потому что, несмотря на то что +один шард отключен, можно получить достаточно положительных ответов с других шардов, +в то время как в 3 стейдже это означает моментальный плохой ответ. diff --git a/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/wrk/3_4xx b/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/wrk/3_4xx index e69de29bb..9eeb76641 100644 --- a/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/wrk/3_4xx +++ b/src/main/java/ru/vk/itmo/test/osipovdaniil/report5/wrk/3_4xx @@ -0,0 +1,114 @@ +./wrk -d 30 -t 1 -c 16 -R 5000 -L -s /home/sbread/Desktop/labs/HLS/2024-highload-dht/src/main/java/ru/vk/itmo/test/osipovdaniil/scripts/put.lua http://localhost:8080 +Running 30s test @ http://localhost:8080 + 1 threads and 16 connections + Thread calibration: mean lat.: 1.338ms, rate sampling interval: 10ms + Thread Stats Avg Stdev Max +/- Stdev + Latency 1.41ms 1.45ms 38.78ms 98.61% + Req/Sec 5.27k 498.44 13.90k 85.24% + Latency Distribution (HdrHistogram - Recorded Latency) + 50.000% 1.26ms + 75.000% 1.75ms + 90.000% 2.14ms + 99.000% 3.46ms + 99.900% 24.51ms + 99.990% 35.17ms + 99.999% 38.49ms +100.000% 38.81ms + + Detailed Percentile spectrum: + Value Percentile TotalCount 1/(1-Percentile) + + 0.101 0.000000 1 1.00 + 0.596 0.100000 9977 1.11 + 0.776 0.200000 19939 1.25 + 0.931 0.300000 29917 1.43 + 1.088 0.400000 39852 1.67 + 1.259 0.500000 49825 2.00 + 1.349 0.550000 54810 2.22 + 1.440 0.600000 59766 2.50 + 1.538 0.650000 64768 2.86 + 1.638 0.700000 69736 3.33 + 1.745 0.750000 74749 4.00 + 1.804 0.775000 77231 4.44 + 1.859 0.800000 79682 5.00 + 1.924 0.825000 82196 5.71 + 1.991 0.850000 84664 6.67 + 2.065 0.875000 87177 8.00 + 2.105 0.887500 88426 8.89 + 2.145 0.900000 89683 10.00 + 2.191 0.912500 90922 11.43 + 2.243 0.925000 92154 13.33 + 2.299 0.937500 93394 16.00 + 2.331 0.943750 94007 17.78 + 2.367 0.950000 94655 20.00 + 2.407 0.956250 95258 22.86 + 2.453 0.962500 95882 26.67 + 2.513 0.968750 96500 32.00 + 2.543 0.971875 96813 35.56 + 2.579 0.975000 97114 40.00 + 2.627 0.978125 97426 45.71 + 2.689 0.981250 97737 53.33 + 2.787 0.984375 98047 64.00 + 2.857 0.985938 98201 71.11 + 2.997 0.987500 98356 80.00 + 3.231 0.989062 98512 91.43 + 3.705 0.990625 98668 106.67 + 4.739 0.992188 98823 128.00 + 5.351 0.992969 98901 142.22 + 6.319 0.993750 98979 160.00 + 8.095 0.994531 99057 182.86 + 9.951 0.995313 99135 213.33 + 11.895 0.996094 99212 256.00 + 12.735 0.996484 99251 284.44 + 14.071 0.996875 99290 320.00 + 15.519 0.997266 99329 365.71 + 16.943 0.997656 99368 426.67 + 18.767 0.998047 99407 512.00 + 19.887 0.998242 99426 568.89 + 20.991 0.998437 99446 640.00 + 22.015 0.998633 99466 731.43 + 23.375 0.998828 99485 853.33 + 24.703 0.999023 99504 1024.00 + 25.759 0.999121 99514 1137.78 + 26.783 0.999219 99524 1280.00 + 27.519 0.999316 99533 1462.86 + 28.431 0.999414 99544 1706.67 + 29.375 0.999512 99553 2048.00 + 30.127 0.999561 99558 2275.56 + 30.447 0.999609 99564 2560.00 + 31.039 0.999658 99567 2925.71 + 31.759 0.999707 99572 3413.33 + 32.703 0.999756 99577 4096.00 + 33.183 0.999780 99580 4551.11 + 33.407 0.999805 99582 5120.00 + 33.503 0.999829 99584 5851.43 + 34.303 0.999854 99587 6826.67 + 34.527 0.999878 99589 8192.00 + 35.167 0.999890 99591 9102.22 + 35.487 0.999902 99592 10240.00 + 35.871 0.999915 99593 11702.86 + 36.191 0.999927 99594 13653.33 + 36.255 0.999939 99595 16384.00 + 36.479 0.999945 99596 18204.44 + 36.543 0.999951 99597 20480.00 + 36.543 0.999957 99597 23405.71 + 37.279 0.999963 99598 27306.67 + 37.279 0.999969 99598 32768.00 + 38.207 0.999973 99599 36408.89 + 38.207 0.999976 99599 40960.00 + 38.207 0.999979 99599 46811.43 + 38.495 0.999982 99600 54613.33 + 38.495 0.999985 99600 65536.00 + 38.495 0.999986 99600 72817.78 + 38.495 0.999988 99600 81920.00 + 38.495 0.999989 99600 93622.86 + 38.815 0.999991 99601 109226.67 + 38.815 1.000000 99601 inf +#[Mean = 1.415, StdDeviation = 1.448] +#[Max = 38.784, Total count = 99601] +#[Buckets = 27, SubBuckets = 2048] +---------------------------------------------------------- + 149816 requests in 30.00s, 10.54MB read + Non-2xx or 3xx responses: 70059 +Requests/sec: 4993.68 +Transfer/sec: 359.88KB