From 2cc3ed7c9a4993b001971a3c960c415a8cf3a684 Mon Sep 17 00:00:00 2001 From: eemhu <125959687+eemhu@users.noreply.github.com> Date: Thu, 19 Mar 2026 10:24:23 +0200 Subject: [PATCH 01/45] remove buffer* --- .../channel/buffer/BufferContainer.java | 69 ------ .../channel/buffer/BufferContainerImpl.java | 87 -------- .../channel/buffer/BufferContainerStub.java | 73 ------- .../net_01/channel/buffer/BufferLease.java | 89 -------- .../channel/buffer/BufferLeaseImpl.java | 136 ------------ .../channel/buffer/BufferLeasePool.java | 203 ------------------ .../channel/buffer/BufferLeaseStub.java | 93 -------- .../context/buffer/BufferLeasePoolTest.java | 119 ---------- 8 files changed, 869 deletions(-) delete mode 100644 src/main/java/com/teragrep/net_01/channel/buffer/BufferContainer.java delete mode 100644 src/main/java/com/teragrep/net_01/channel/buffer/BufferContainerImpl.java delete mode 100644 src/main/java/com/teragrep/net_01/channel/buffer/BufferContainerStub.java delete mode 100644 src/main/java/com/teragrep/net_01/channel/buffer/BufferLease.java delete mode 100644 src/main/java/com/teragrep/net_01/channel/buffer/BufferLeaseImpl.java delete mode 100644 src/main/java/com/teragrep/net_01/channel/buffer/BufferLeasePool.java delete mode 100644 src/main/java/com/teragrep/net_01/channel/buffer/BufferLeaseStub.java delete mode 100644 src/test/java/com/teragrep/net_01/channel/context/buffer/BufferLeasePoolTest.java diff --git a/src/main/java/com/teragrep/net_01/channel/buffer/BufferContainer.java b/src/main/java/com/teragrep/net_01/channel/buffer/BufferContainer.java deleted file mode 100644 index 8865e89..0000000 --- a/src/main/java/com/teragrep/net_01/channel/buffer/BufferContainer.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Java Zero Copy Networking Library net_01 - * Copyright (C) 2024 Suomen Kanuuna Oy - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - * - * Additional permission under GNU Affero General Public License version 3 - * section 7 - * - * If you modify this Program, or any covered work, by linking or combining it - * with other code, such other code is not for that reason alone subject to any - * of the requirements of the GNU Affero GPL version 3 as long as this Program - * is the same Program as licensed from Suomen Kanuuna Oy without any additional - * modifications. - * - * Supplemented terms under GNU Affero General Public License version 3 - * section 7 - * - * Origin of the software must be attributed to Suomen Kanuuna Oy. Any modified - * versions must be marked as "Modified version of" The Program. - * - * Names of the licensors and authors may not be used for publicity purposes. - * - * No rights are granted for use of trade names, trademarks, or service marks - * which are in The Program if any. - * - * Licensee must indemnify licensors and authors for any liability that these - * contractual assumptions impose on licensors and authors. - * - * To the extent this program is licensed as part of the Commercial versions of - * Teragrep, the applicable Commercial License may apply to this file if you as - * a licensee so wish it. - */ -package com.teragrep.net_01.channel.buffer; - -import java.nio.ByteBuffer; - -/** - * BufferContainer is a decorator for {@link ByteBuffer} with an id. - */ -public interface BufferContainer { - - /** - * @return id of the buffer - */ - long id(); - - /** - * @return encapsulated {@link ByteBuffer}. - */ - ByteBuffer buffer(); - - /** - * @return is this a stub implementation. - */ - boolean isStub(); -} diff --git a/src/main/java/com/teragrep/net_01/channel/buffer/BufferContainerImpl.java b/src/main/java/com/teragrep/net_01/channel/buffer/BufferContainerImpl.java deleted file mode 100644 index 6ac9924..0000000 --- a/src/main/java/com/teragrep/net_01/channel/buffer/BufferContainerImpl.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Java Zero Copy Networking Library net_01 - * Copyright (C) 2024 Suomen Kanuuna Oy - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - * - * Additional permission under GNU Affero General Public License version 3 - * section 7 - * - * If you modify this Program, or any covered work, by linking or combining it - * with other code, such other code is not for that reason alone subject to any - * of the requirements of the GNU Affero GPL version 3 as long as this Program - * is the same Program as licensed from Suomen Kanuuna Oy without any additional - * modifications. - * - * Supplemented terms under GNU Affero General Public License version 3 - * section 7 - * - * Origin of the software must be attributed to Suomen Kanuuna Oy. Any modified - * versions must be marked as "Modified version of" The Program. - * - * Names of the licensors and authors may not be used for publicity purposes. - * - * No rights are granted for use of trade names, trademarks, or service marks - * which are in The Program if any. - * - * Licensee must indemnify licensors and authors for any liability that these - * contractual assumptions impose on licensors and authors. - * - * To the extent this program is licensed as part of the Commercial versions of - * Teragrep, the applicable Commercial License may apply to this file if you as - * a licensee so wish it. - */ -package com.teragrep.net_01.channel.buffer; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.nio.ByteBuffer; - -/** - * Decorator for {@link ByteBuffer} with a synchronized access for it. - */ -final class BufferContainerImpl implements BufferContainer { - - private static final Logger LOGGER = LoggerFactory.getLogger(BufferContainerImpl.class); - private final long id; - private final ByteBuffer buffer; - - BufferContainerImpl(long id, ByteBuffer buffer) { - this.id = id; - this.buffer = buffer; - } - - @Override - public long id() { - return id; - } - - @Override - public synchronized ByteBuffer buffer() { - return buffer; - } - - @Override - public String toString() { - return "BufferContainer{" + "buffer=" + buffer + ", id=" + id + '}'; - } - - @Override - public boolean isStub() { - LOGGER.debug("id <{}>", id); - return false; - } -} diff --git a/src/main/java/com/teragrep/net_01/channel/buffer/BufferContainerStub.java b/src/main/java/com/teragrep/net_01/channel/buffer/BufferContainerStub.java deleted file mode 100644 index 1171305..0000000 --- a/src/main/java/com/teragrep/net_01/channel/buffer/BufferContainerStub.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Java Zero Copy Networking Library net_01 - * Copyright (C) 2024 Suomen Kanuuna Oy - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - * - * Additional permission under GNU Affero General Public License version 3 - * section 7 - * - * If you modify this Program, or any covered work, by linking or combining it - * with other code, such other code is not for that reason alone subject to any - * of the requirements of the GNU Affero GPL version 3 as long as this Program - * is the same Program as licensed from Suomen Kanuuna Oy without any additional - * modifications. - * - * Supplemented terms under GNU Affero General Public License version 3 - * section 7 - * - * Origin of the software must be attributed to Suomen Kanuuna Oy. Any modified - * versions must be marked as "Modified version of" The Program. - * - * Names of the licensors and authors may not be used for publicity purposes. - * - * No rights are granted for use of trade names, trademarks, or service marks - * which are in The Program if any. - * - * Licensee must indemnify licensors and authors for any liability that these - * contractual assumptions impose on licensors and authors. - * - * To the extent this program is licensed as part of the Commercial versions of - * Teragrep, the applicable Commercial License may apply to this file if you as - * a licensee so wish it. - */ -package com.teragrep.net_01.channel.buffer; - -import java.nio.ByteBuffer; - -/** - * Stub implementation of the {@link BufferContainer}. - */ -final class BufferContainerStub implements BufferContainer { - - BufferContainerStub() { - - } - - @Override - public long id() { - throw new IllegalStateException("BufferContainerStub does not have an id!"); - } - - @Override - public ByteBuffer buffer() { - throw new IllegalStateException("BufferContainerStub does not allow access to the buffer!"); - } - - @Override - public boolean isStub() { - return true; - } -} diff --git a/src/main/java/com/teragrep/net_01/channel/buffer/BufferLease.java b/src/main/java/com/teragrep/net_01/channel/buffer/BufferLease.java deleted file mode 100644 index 152a65e..0000000 --- a/src/main/java/com/teragrep/net_01/channel/buffer/BufferLease.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Java Zero Copy Networking Library net_01 - * Copyright (C) 2024 Suomen Kanuuna Oy - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - * - * Additional permission under GNU Affero General Public License version 3 - * section 7 - * - * If you modify this Program, or any covered work, by linking or combining it - * with other code, such other code is not for that reason alone subject to any - * of the requirements of the GNU Affero GPL version 3 as long as this Program - * is the same Program as licensed from Suomen Kanuuna Oy without any additional - * modifications. - * - * Supplemented terms under GNU Affero General Public License version 3 - * section 7 - * - * Origin of the software must be attributed to Suomen Kanuuna Oy. Any modified - * versions must be marked as "Modified version of" The Program. - * - * Names of the licensors and authors may not be used for publicity purposes. - * - * No rights are granted for use of trade names, trademarks, or service marks - * which are in The Program if any. - * - * Licensee must indemnify licensors and authors for any liability that these - * contractual assumptions impose on licensors and authors. - * - * To the extent this program is licensed as part of the Commercial versions of - * Teragrep, the applicable Commercial License may apply to this file if you as - * a licensee so wish it. - */ -package com.teragrep.net_01.channel.buffer; - -import java.nio.ByteBuffer; - -/** - * BufferLease is a decorator for {@link BufferContainer} with reference counter - */ -public interface BufferLease { - - /** - * @return identity of the decorated {@link BufferContainer}. - */ - long id(); - - /** - * @return current reference count. - */ - long refs(); - - /** - * @return encapsulated buffer of the {@link BufferContainer}. - */ - ByteBuffer buffer(); - - /** - * Add reference, throws {@link IllegalStateException} if lease has expired. - */ - void addRef() throws IllegalStateException; - - /** - * Remove reference, throws {@link IllegalStateException} if lease has expired. - */ - void removeRef() throws IllegalStateException; - - /** - * @return status of the lease, {@code true} indicates that the lease has expired. - */ - boolean isTerminated(); - - /** - * @return is this a stub implementation. - */ - boolean isStub(); -} diff --git a/src/main/java/com/teragrep/net_01/channel/buffer/BufferLeaseImpl.java b/src/main/java/com/teragrep/net_01/channel/buffer/BufferLeaseImpl.java deleted file mode 100644 index c7001b9..0000000 --- a/src/main/java/com/teragrep/net_01/channel/buffer/BufferLeaseImpl.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Java Zero Copy Networking Library net_01 - * Copyright (C) 2024 Suomen Kanuuna Oy - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - * - * Additional permission under GNU Affero General Public License version 3 - * section 7 - * - * If you modify this Program, or any covered work, by linking or combining it - * with other code, such other code is not for that reason alone subject to any - * of the requirements of the GNU Affero GPL version 3 as long as this Program - * is the same Program as licensed from Suomen Kanuuna Oy without any additional - * modifications. - * - * Supplemented terms under GNU Affero General Public License version 3 - * section 7 - * - * Origin of the software must be attributed to Suomen Kanuuna Oy. Any modified - * versions must be marked as "Modified version of" The Program. - * - * Names of the licensors and authors may not be used for publicity purposes. - * - * No rights are granted for use of trade names, trademarks, or service marks - * which are in The Program if any. - * - * Licensee must indemnify licensors and authors for any liability that these - * contractual assumptions impose on licensors and authors. - * - * To the extent this program is licensed as part of the Commercial versions of - * Teragrep, the applicable Commercial License may apply to this file if you as - * a licensee so wish it. - */ -package com.teragrep.net_01.channel.buffer; - -import java.nio.ByteBuffer; -import java.util.concurrent.Phaser; - -/** - * Decorator for {@link BufferContainer} that automatically clears (frees) the encapsulated {@link ByteBuffer} and - * returns the {@link BufferContainer} to {@link BufferLeasePool} when reference count hits zero. Starts with one - * initial reference. Internally uses a {@link Phaser} to track reference count in a non-blocking way. - */ -final class BufferLeaseImpl implements BufferLease { - - private final BufferContainer bufferContainer; - private final Phaser phaser; - private final BufferLeasePool bufferLeasePool; - - BufferLeaseImpl(BufferContainer bc, BufferLeasePool bufferLeasePool) { - this.bufferContainer = bc; - this.bufferLeasePool = bufferLeasePool; - - // initial registered parties set to 1 - this.phaser = new ClearingPhaser(1); - } - - @Override - public long id() { - return bufferContainer.id(); - } - - @Override - public long refs() { - // initial number of registered parties is 1 - return phaser.getRegisteredParties(); - } - - @Override - public ByteBuffer buffer() { - if (phaser.isTerminated()) { - throw new IllegalStateException( - "Cannot return wrapped ByteBuffer, BufferLease phaser was already terminated!" - ); - } - return bufferContainer.buffer(); - } - - @Override - public void addRef() { - if (phaser.register() < 0) { - throw new IllegalStateException("Cannot add reference, BufferLease phaser was already terminated!"); - } - } - - @Override - public void removeRef() { - if (phaser.arriveAndDeregister() < 0) { - throw new IllegalStateException("Cannot remove reference, BufferLease phaser was already terminated!"); - } - } - - @Override - public boolean isTerminated() { - return phaser.isTerminated(); - } - - @Override - public boolean isStub() { - return bufferContainer.isStub(); - } - - /** - * Phaser that clears the buffer on termination (registeredParties=0) - */ - private class ClearingPhaser extends Phaser { - - public ClearingPhaser(int i) { - super(i); - } - - @Override - protected boolean onAdvance(int phase, int registeredParties) { - boolean rv = false; - if (registeredParties == 0) { - buffer().clear(); - bufferLeasePool.internalOffer(bufferContainer); - rv = true; - } - return rv; - } - } - -} diff --git a/src/main/java/com/teragrep/net_01/channel/buffer/BufferLeasePool.java b/src/main/java/com/teragrep/net_01/channel/buffer/BufferLeasePool.java deleted file mode 100644 index db1c66c..0000000 --- a/src/main/java/com/teragrep/net_01/channel/buffer/BufferLeasePool.java +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Java Zero Copy Networking Library net_01 - * Copyright (C) 2024 Suomen Kanuuna Oy - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - * - * Additional permission under GNU Affero General Public License version 3 - * section 7 - * - * If you modify this Program, or any covered work, by linking or combining it - * with other code, such other code is not for that reason alone subject to any - * of the requirements of the GNU Affero GPL version 3 as long as this Program - * is the same Program as licensed from Suomen Kanuuna Oy without any additional - * modifications. - * - * Supplemented terms under GNU Affero General Public License version 3 - * section 7 - * - * Origin of the software must be attributed to Suomen Kanuuna Oy. Any modified - * versions must be marked as "Modified version of" The Program. - * - * Names of the licensors and authors may not be used for publicity purposes. - * - * No rights are granted for use of trade names, trademarks, or service marks - * which are in The Program if any. - * - * Licensee must indemnify licensors and authors for any liability that these - * contractual assumptions impose on licensors and authors. - * - * To the extent this program is licensed as part of the Commercial versions of - * Teragrep, the applicable Commercial License may apply to this file if you as - * a licensee so wish it. - */ -package com.teragrep.net_01.channel.buffer; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.nio.ByteBuffer; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; -import java.util.function.Supplier; - -/** - * Non-blocking pool for {@link BufferContainer} objects. All objects in the pool are {@link ByteBuffer#clear()}ed - * before returning to the pool by {@link BufferLease}. - */ -public final class BufferLeasePool { - // TODO create tests - - private static final Logger LOGGER = LoggerFactory.getLogger(BufferLeasePool.class); - - private final Supplier byteBufferSupplier; - - private final ConcurrentLinkedQueue queue; - - private final BufferLease bufferLeaseStub; - private final BufferContainer bufferContainerStub; - private final AtomicBoolean close; - - private final int segmentSize; - - private final AtomicLong bufferId; - - private final Lock lock; - - // TODO check locking pattern, addRef in BufferLease can escape offer's check and cause dirty in pool? - public BufferLeasePool() { - this.segmentSize = 4096; - this.byteBufferSupplier = () -> ByteBuffer.allocateDirect(segmentSize); // TODO configurable extents - this.queue = new ConcurrentLinkedQueue<>(); - this.bufferLeaseStub = new BufferLeaseStub(); - this.bufferContainerStub = new BufferContainerStub(); - this.close = new AtomicBoolean(); - this.bufferId = new AtomicLong(); - this.lock = new ReentrantLock(); - } - - private BufferLease take() { - // get or create - BufferContainer bufferContainer = queue.poll(); - BufferLease bufferLease; - if (bufferContainer == null) { - // if queue is empty or stub object, create a new BufferContainer and BufferLease. - bufferLease = new BufferLeaseImpl( - new BufferContainerImpl(bufferId.incrementAndGet(), byteBufferSupplier.get()), - this - ); - } - else { - // otherwise, wrap bufferContainer with phaser decorator (bufferLease) - bufferLease = new BufferLeaseImpl(bufferContainer, this); - } - - if (LOGGER.isDebugEnabled()) { - LOGGER - .debug( - "returning bufferLease id <{}> with refs <{}> at buffer position <{}>", bufferLease.id(), - bufferLease.refs(), bufferLease.buffer().position() - ); - } - - if (bufferLease.buffer().position() != 0) { - throw new IllegalStateException("Dirty buffer in pool, terminating!"); - } - - return bufferLease; - - } - - /** - * @param size minimum size of the {@link BufferLease}s requested. - * @return list of {@link BufferLease}s meeting or exceeding the size requested. - */ - public List take(long size) { - if (close.get()) { - return Collections.singletonList(bufferLeaseStub); - } - - LOGGER.debug("requesting take with size <{}>", size); - long currentSize = 0; - List bufferLeases = new LinkedList<>(); - while (currentSize < size) { - BufferLease bufferLease = take(); - bufferLeases.add(bufferLease); - currentSize = currentSize + bufferLease.buffer().capacity(); - - } - return bufferLeases; - - } - - /** - * return {@link BufferContainer} into the pool. - * - * @param bufferContainer {@link BufferContainer} from {@link BufferLease} which has been - * {@link ByteBuffer#clear()}ed. - */ - void internalOffer(BufferContainer bufferContainer) { - // Add buffer back to pool if it is not a stub object - if (!bufferContainer.isStub()) { - queue.add(bufferContainer); - } - - if (close.get()) { - LOGGER.debug("closing in offer"); - while (!queue.isEmpty()) { - if (lock.tryLock()) { - queue.clear(); - lock.unlock(); - } - else { - break; - } - } - } - if (LOGGER.isDebugEnabled()) { - long queueSegments = queue.size(); - long queueBytes = queueSegments * segmentSize; - LOGGER.debug("offer complete, queueSegments <{}>, queueBytes <{}>", queueSegments, queueBytes); - } - } - - /** - * Closes the {@link BufferLeasePool}, deallocating currently residing {@link BufferContainer}s and future ones when - * returned. - */ - public void close() { - LOGGER.debug("close called"); - close.set(true); - - // close all that are in the pool right now - internalOffer(bufferContainerStub); - - } - - /** - * Estimate the pool size, due to non-blocking nature of the pool, this is only an estimate. - * - * @return estimate of the pool size, counting only the residing buffers. - */ - public int estimatedSize() { - return queue.size(); - } -} diff --git a/src/main/java/com/teragrep/net_01/channel/buffer/BufferLeaseStub.java b/src/main/java/com/teragrep/net_01/channel/buffer/BufferLeaseStub.java deleted file mode 100644 index ad85f04..0000000 --- a/src/main/java/com/teragrep/net_01/channel/buffer/BufferLeaseStub.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Java Zero Copy Networking Library net_01 - * Copyright (C) 2024 Suomen Kanuuna Oy - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - * - * Additional permission under GNU Affero General Public License version 3 - * section 7 - * - * If you modify this Program, or any covered work, by linking or combining it - * with other code, such other code is not for that reason alone subject to any - * of the requirements of the GNU Affero GPL version 3 as long as this Program - * is the same Program as licensed from Suomen Kanuuna Oy without any additional - * modifications. - * - * Supplemented terms under GNU Affero General Public License version 3 - * section 7 - * - * Origin of the software must be attributed to Suomen Kanuuna Oy. Any modified - * versions must be marked as "Modified version of" The Program. - * - * Names of the licensors and authors may not be used for publicity purposes. - * - * No rights are granted for use of trade names, trademarks, or service marks - * which are in The Program if any. - * - * Licensee must indemnify licensors and authors for any liability that these - * contractual assumptions impose on licensors and authors. - * - * To the extent this program is licensed as part of the Commercial versions of - * Teragrep, the applicable Commercial License may apply to this file if you as - * a licensee so wish it. - */ -package com.teragrep.net_01.channel.buffer; - -import java.nio.ByteBuffer; - -/** - * Stub implementation of the {@link BufferLease} - */ -final class BufferLeaseStub implements BufferLease { - - BufferLeaseStub() { - - } - - @Override - public long id() { - throw new IllegalStateException("BufferLeaseStub does not have an id!"); - } - - @Override - public long refs() { - throw new IllegalStateException("BufferLeaseStub does not have refs!"); - } - - @Override - public ByteBuffer buffer() { - throw new IllegalStateException("BufferLeaseStub does not have a buffer!"); - } - - @Override - public void addRef() { - throw new IllegalStateException("BufferLeaseStub does not allow adding refs!"); - } - - @Override - public void removeRef() { - throw new IllegalStateException("BufferLeaseStub does not allow removing refs!"); - } - - @Override - public boolean isTerminated() { - throw new IllegalStateException("BufferLeaseStub does not have ref count!"); - } - - @Override - public boolean isStub() { - return true; - } -} diff --git a/src/test/java/com/teragrep/net_01/channel/context/buffer/BufferLeasePoolTest.java b/src/test/java/com/teragrep/net_01/channel/context/buffer/BufferLeasePoolTest.java deleted file mode 100644 index 5dbaea3..0000000 --- a/src/test/java/com/teragrep/net_01/channel/context/buffer/BufferLeasePoolTest.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Java Zero Copy Networking Library net_01 - * Copyright (C) 2024 Suomen Kanuuna Oy - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - * - * Additional permission under GNU Affero General Public License version 3 - * section 7 - * - * If you modify this Program, or any covered work, by linking or combining it - * with other code, such other code is not for that reason alone subject to any - * of the requirements of the GNU Affero GPL version 3 as long as this Program - * is the same Program as licensed from Suomen Kanuuna Oy without any additional - * modifications. - * - * Supplemented terms under GNU Affero General Public License version 3 - * section 7 - * - * Origin of the software must be attributed to Suomen Kanuuna Oy. Any modified - * versions must be marked as "Modified version of" The Program. - * - * Names of the licensors and authors may not be used for publicity purposes. - * - * No rights are granted for use of trade names, trademarks, or service marks - * which are in The Program if any. - * - * Licensee must indemnify licensors and authors for any liability that these - * contractual assumptions impose on licensors and authors. - * - * To the extent this program is licensed as part of the Commercial versions of - * Teragrep, the applicable Commercial License may apply to this file if you as - * a licensee so wish it. - */ -package com.teragrep.net_01.channel.context.buffer; - -import com.teragrep.net_01.channel.buffer.BufferLease; -import com.teragrep.net_01.channel.buffer.BufferLeasePool; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -import java.nio.ByteBuffer; -import java.util.List; - -public class BufferLeasePoolTest { - - @Test - public void testPool() { - BufferLeasePool bufferLeasePool = new BufferLeasePool(); - List leases = bufferLeasePool.take(1); - - Assertions.assertEquals(1, leases.size()); - - Assertions.assertEquals(0, bufferLeasePool.estimatedSize()); // none in the pool - - BufferLease lease = leases.get(0); - - Assertions.assertFalse(lease.isStub()); - - Assertions.assertFalse(lease.isTerminated()); // initially 1 refs - - Assertions.assertEquals(1, lease.refs()); // check initial 1 ref - - lease.addRef(); - - Assertions.assertEquals(2, lease.refs()); - - lease.buffer().put((byte) 'x'); - - Assertions.assertEquals(1, lease.buffer().position()); - - lease.buffer().flip(); - - Assertions.assertEquals(0, lease.buffer().position()); - - Assertions.assertEquals(1, lease.buffer().limit()); - - Assertions.assertEquals((byte) 'x', lease.buffer().get()); - - Assertions.assertEquals(1, lease.buffer().position()); - - Assertions.assertEquals(2, lease.refs()); - - lease.removeRef(); - - Assertions.assertFalse(lease.isTerminated()); // initial ref must be still in place - - Assertions.assertEquals(1, lease.refs()); // initial ref must be still in - - ByteBuffer buffer = lease.buffer(); // get a hold of a reference - - lease.removeRef(); // removes initial ref - - Assertions.assertEquals(1, bufferLeasePool.estimatedSize()); // the one offered must be there - - Assertions.assertTrue(lease.isTerminated()); // no refs - - Assertions.assertThrows(IllegalStateException.class, lease::buffer); - - Assertions.assertEquals(buffer.capacity(), buffer.limit()); - - Assertions.assertEquals(0, buffer.position()); - - bufferLeasePool.close(); - - Assertions.assertEquals(0, bufferLeasePool.estimatedSize()); - } -} From d9b62d76aad81f0e25edf7b1b947dc8566279f7a Mon Sep 17 00:00:00 2001 From: eemhu <125959687+eemhu@users.noreply.github.com> Date: Thu, 19 Mar 2026 10:24:42 +0200 Subject: [PATCH 02/45] replace with buf_01 usages --- .../buffer/writable/WriteableLeaseful.java | 18 ++++-- .../net_01/channel/context/Clock.java | 6 +- .../context/EstablishedContextImpl.java | 14 +++-- .../net_01/channel/context/IngressImpl.java | 59 ++++++++----------- .../net_01/channel/socket/EncryptionInfo.java | 7 +-- .../channel/socket/EncryptionInfoStub.java | 2 +- .../channel/socket/EncryptionInfoTLS.java | 4 +- 7 files changed, 55 insertions(+), 55 deletions(-) diff --git a/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableLeaseful.java b/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableLeaseful.java index 9c79a4c..bc8c201 100644 --- a/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableLeaseful.java +++ b/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableLeaseful.java @@ -45,10 +45,13 @@ */ package com.teragrep.net_01.channel.buffer.writable; -import com.teragrep.net_01.channel.buffer.BufferLease; +import com.teragrep.buf_01.buffer.lease.OpenableLease; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.lang.foreign.MemorySegment; import java.nio.ByteBuffer; import java.util.List; @@ -57,9 +60,9 @@ public final class WriteableLeaseful implements Writeable { private static final Logger LOGGER = LoggerFactory.getLogger(WriteableLeaseful.class); private final Writeable writeable; - private final List leases; + private final List> leases; - public WriteableLeaseful(Writeable writeable, List leases) { + public WriteableLeaseful(Writeable writeable, List> leases) { this.writeable = writeable; this.leases = leases; } @@ -83,11 +86,16 @@ public boolean isStub() { public void close() { writeable.close(); // TODO subleases for fragments - for (BufferLease bufferLease : leases) { + for (OpenableLease bufferLease : leases) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("releasing id <{}> with refs <{}>", bufferLease.id(), bufferLease.refs()); } - bufferLease.removeRef(); + // FIXME: bufferLease.removeRef(); + try { + bufferLease.close(); + } catch (Exception e) { + throw new RuntimeException(e); + } } } diff --git a/src/main/java/com/teragrep/net_01/channel/context/Clock.java b/src/main/java/com/teragrep/net_01/channel/context/Clock.java index 36f86a6..76d1ca8 100644 --- a/src/main/java/com/teragrep/net_01/channel/context/Clock.java +++ b/src/main/java/com/teragrep/net_01/channel/context/Clock.java @@ -45,7 +45,9 @@ */ package com.teragrep.net_01.channel.context; -import com.teragrep.net_01.channel.buffer.BufferLease; +import com.teragrep.buf_01.buffer.lease.Lease; + +import java.lang.foreign.MemorySegment; public interface Clock extends AutoCloseable { @@ -53,5 +55,5 @@ public interface Clock extends AutoCloseable { * @param bufferLease to be consumed by the Clock. Clock or it's subsequent actions must close all BufferLease's it * receives otherwise encapsulated buffers are not reusable and memory allocator consumes time. */ - void advance(BufferLease bufferLease); + void advance(Lease bufferLease); } diff --git a/src/main/java/com/teragrep/net_01/channel/context/EstablishedContextImpl.java b/src/main/java/com/teragrep/net_01/channel/context/EstablishedContextImpl.java index 80202d7..fc18e1c 100644 --- a/src/main/java/com/teragrep/net_01/channel/context/EstablishedContextImpl.java +++ b/src/main/java/com/teragrep/net_01/channel/context/EstablishedContextImpl.java @@ -45,12 +45,16 @@ */ package com.teragrep.net_01.channel.context; +import com.teragrep.buf_01.buffer.lease.MemorySegmentLeaseStub; +import com.teragrep.buf_01.buffer.pool.OpeningPool; +import com.teragrep.buf_01.buffer.supply.ArenaMemorySegmentLeaseSupplier; import com.teragrep.net_01.channel.socket.Socket; -import com.teragrep.net_01.channel.buffer.BufferLeasePool; +import com.teragrep.poj_01.pool.UnboundPool; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; +import java.lang.foreign.Arena; import java.nio.channels.CancelledKeyException; import java.nio.channels.SelectionKey; import java.nio.channels.spi.AbstractSelectableChannel; @@ -71,7 +75,7 @@ final class EstablishedContextImpl implements EstablishedContext { private final Socket socket; private final InterestOps interestOps; - private final BufferLeasePool bufferLeasePool; + private final OpeningPool memorySegmentLeasePool; private final Ingress ingress; private final Egress egress; @@ -80,8 +84,8 @@ final class EstablishedContextImpl implements EstablishedContext { this.executorService = executorService; this.socket = socket; - this.bufferLeasePool = new BufferLeasePool(); - this.ingress = new IngressImpl(this, this.bufferLeasePool); + this.memorySegmentLeasePool = new OpeningPool(new UnboundPool<>(new ArenaMemorySegmentLeaseSupplier(Arena.ofShared(), 4096), new MemorySegmentLeaseStub())); + this.ingress = new IngressImpl(this, this.memorySegmentLeasePool); this.egress = new EgressImpl(this); } @@ -111,7 +115,7 @@ public void close() { LOGGER.warn("IOException <{}> in close", ioe.getMessage()); } - bufferLeasePool.close(); + memorySegmentLeasePool.close(); } @Override diff --git a/src/main/java/com/teragrep/net_01/channel/context/IngressImpl.java b/src/main/java/com/teragrep/net_01/channel/context/IngressImpl.java index 534c913..4feb360 100644 --- a/src/main/java/com/teragrep/net_01/channel/context/IngressImpl.java +++ b/src/main/java/com/teragrep/net_01/channel/context/IngressImpl.java @@ -45,14 +45,17 @@ */ package com.teragrep.net_01.channel.context; -import com.teragrep.net_01.channel.buffer.BufferLease; -import com.teragrep.net_01.channel.buffer.BufferLeasePool; +import com.teragrep.buf_01.buffer.lease.OpenableLease; +import com.teragrep.buf_01.buffer.pool.LeaseMultiGet; +import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; +import com.teragrep.poj_01.pool.Pool; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import tlschannel.NeedsReadException; import tlschannel.NeedsWriteException; import java.io.IOException; +import java.lang.foreign.MemorySegment; import java.nio.ByteBuffer; import java.nio.channels.CancelledKeyException; import java.util.LinkedList; @@ -68,18 +71,18 @@ final class IngressImpl implements Ingress { private static final Logger LOGGER = LoggerFactory.getLogger(IngressImpl.class); private final EstablishedContextImpl establishedContext; - private final BufferLeasePool bufferLeasePool; + private final Pool> memorySegmentLeasePool; - private final LinkedList activeBuffers; + private final LinkedList activeBuffers; private final Lock lock; // tls public final AtomicBoolean needWrite; private final List interestedClocks; - IngressImpl(EstablishedContextImpl establishedContext, BufferLeasePool bufferLeasePool) { + IngressImpl(EstablishedContextImpl establishedContext, Pool> memorySegmentLeasePool) { this.establishedContext = establishedContext; - this.bufferLeasePool = bufferLeasePool; + this.memorySegmentLeasePool = memorySegmentLeasePool; this.activeBuffers = new LinkedList<>(); this.lock = new ReentrantLock(); @@ -109,8 +112,7 @@ public void run() { boolean continueReading = true; while (!activeBuffers.isEmpty()) { // IMPORTANT: current tls implementation will skip bytes if BufferLeases are not fully consumed. - BufferLease bufferLease = activeBuffers.removeFirst(); - bufferLease.addRef(); + TrackedMemorySegmentLease bufferLease = activeBuffers.removeFirst(); LOGGER .debug( "submitting buffer <{}> from activeBuffers <{}> to relpFrame", bufferLease, @@ -120,12 +122,6 @@ public void run() { if (!interestedClocks.isEmpty()) { for (Clock clock : interestedClocks) { clock.advance(bufferLease); - - if (bufferLease.buffer().hasRemaining()) { - // shared buffer between clocks, ready for another - bufferLease.addRef(); - } - } } @@ -134,19 +130,19 @@ public void run() { } LOGGER.debug("clock returned continueReading <{}>", continueReading); - if (bufferLease.buffer().hasRemaining()) { + + if (bufferLease.hasNext()) { // return back as it has some remaining LOGGER.debug("pushBack bufferLease id <{}>", bufferLease.id()); activeBuffers.push(bufferLease); if (LOGGER.isDebugEnabled()) { LOGGER .debug( - "buffer.buffer <{}>, buffer.buffer().hasRemaining() <{}> returned it to activeBuffers <{}>", - bufferLease.buffer(), bufferLease.buffer().hasRemaining(), activeBuffers + "buffer.leasedObject <{}>, buffer.hasNext <{}> returned it to activeBuffers <{}>", + bufferLease.leasedObject(), bufferLease.hasNext(), activeBuffers ); } } - bufferLease.removeRef(); if (!continueReading) { break; } @@ -230,41 +226,32 @@ else if (readBytes < 0) { } private long readData() throws IOException { - long readBytes = 0; + long readBytes; - List bufferLeases = bufferLeasePool.take(4); + List> bufferLeases = new LeaseMultiGet(memorySegmentLeasePool).get(4); List byteBufferList = new LinkedList<>(); - for (BufferLease bufferLease : bufferLeases) { + for (OpenableLease bufferLease : bufferLeases) { if (bufferLease.isStub()) { continue; } - byteBufferList.add(bufferLease.buffer()); + byteBufferList.add(bufferLease.leasedObject().asByteBuffer()); } ByteBuffer[] byteBufferArray = byteBufferList.toArray(new ByteBuffer[0]); readBytes = establishedContext.socket().read(byteBufferArray); + // TODO: Figure out a way to see which buffers were written into. + // Right now, buffers that are not written into are pushed into activeBuffers. - activateBuffers(bufferLeases); + for (final OpenableLease bufferLease : bufferLeases) { + activeBuffers.push(new TrackedMemorySegmentLease(bufferLease)); + } LOGGER.debug("establishedContext.read got <{}> bytes from socket", readBytes); return readBytes; } - private void activateBuffers(List bufferLeases) { - for (BufferLease bufferLease : bufferLeases) { - if (bufferLease.buffer().position() != 0) { - bufferLease.buffer().flip(); - activeBuffers.add(bufferLease); - } - else { - // unused buffer, releasing back to pool - bufferLease.removeRef(); - } - } - } - public AtomicBoolean needWrite() { return needWrite; } diff --git a/src/main/java/com/teragrep/net_01/channel/socket/EncryptionInfo.java b/src/main/java/com/teragrep/net_01/channel/socket/EncryptionInfo.java index 52561e9..ad0621a 100644 --- a/src/main/java/com/teragrep/net_01/channel/socket/EncryptionInfo.java +++ b/src/main/java/com/teragrep/net_01/channel/socket/EncryptionInfo.java @@ -47,7 +47,6 @@ import javax.net.ssl.SSLPeerUnverifiedException; import javax.net.ssl.SSLSession; -import javax.security.cert.X509Certificate; import java.security.Principal; import java.security.cert.Certificate; @@ -86,11 +85,11 @@ public interface EncryptionInfo { /** * throws IllegalStateException if isEncrypted returns false - * - * @return see {@link SSLSession#getPeerCertificateChain()} + * + * @return see {@link SSLSession#getPeerCertificates()} * @throws SSLPeerUnverifiedException */ - X509Certificate[] getPeerCertificateChain() throws SSLPeerUnverifiedException; + Certificate[] getPeerCertificateChain() throws SSLPeerUnverifiedException; /** * throws IllegalStateException if isEncrypted returns false diff --git a/src/main/java/com/teragrep/net_01/channel/socket/EncryptionInfoStub.java b/src/main/java/com/teragrep/net_01/channel/socket/EncryptionInfoStub.java index d7d32cf..9e059d4 100644 --- a/src/main/java/com/teragrep/net_01/channel/socket/EncryptionInfoStub.java +++ b/src/main/java/com/teragrep/net_01/channel/socket/EncryptionInfoStub.java @@ -80,7 +80,7 @@ public Principal getLocalPrincipal() { } @Override - public X509Certificate[] getPeerCertificateChain() throws SSLPeerUnverifiedException { + public Certificate[] getPeerCertificateChain() throws SSLPeerUnverifiedException { throw new IllegalStateException("not encrypted"); } diff --git a/src/main/java/com/teragrep/net_01/channel/socket/EncryptionInfoTLS.java b/src/main/java/com/teragrep/net_01/channel/socket/EncryptionInfoTLS.java index 0e7c791..1517e07 100644 --- a/src/main/java/com/teragrep/net_01/channel/socket/EncryptionInfoTLS.java +++ b/src/main/java/com/teragrep/net_01/channel/socket/EncryptionInfoTLS.java @@ -81,8 +81,8 @@ public Principal getLocalPrincipal() { } @Override - public X509Certificate[] getPeerCertificateChain() throws SSLPeerUnverifiedException { - return tlsChannel.getSslEngine().getSession().getPeerCertificateChain(); + public Certificate[] getPeerCertificateChain() throws SSLPeerUnverifiedException { + return tlsChannel.getSslEngine().getSession().getPeerCertificates(); } @Override From 23c699ed4b08844d371cd596cd54f4e3c84a8d06 Mon Sep 17 00:00:00 2001 From: eemhu <125959687+eemhu@users.noreply.github.com> Date: Thu, 19 Mar 2026 10:24:54 +0200 Subject: [PATCH 03/45] introduce TrackedMemorySegmentLease --- .../buffer/TrackedMemorySegmentLease.java | 76 +++++++++++++++++++ .../buffer/TrackedMemorySegmentLeaseTest.java | 36 +++++++++ 2 files changed, 112 insertions(+) create mode 100644 src/main/java/com/teragrep/net_01/channel/buffer/TrackedMemorySegmentLease.java create mode 100644 src/test/java/com/teragrep/net_01/channel/context/buffer/TrackedMemorySegmentLeaseTest.java diff --git a/src/main/java/com/teragrep/net_01/channel/buffer/TrackedMemorySegmentLease.java b/src/main/java/com/teragrep/net_01/channel/buffer/TrackedMemorySegmentLease.java new file mode 100644 index 0000000..b66d9fb --- /dev/null +++ b/src/main/java/com/teragrep/net_01/channel/buffer/TrackedMemorySegmentLease.java @@ -0,0 +1,76 @@ +package com.teragrep.net_01.channel.buffer; + +import com.teragrep.buf_01.buffer.lease.Lease; + +import java.lang.foreign.MemorySegment; +import java.lang.foreign.ValueLayout; +import java.util.Iterator; +import java.util.concurrent.atomic.AtomicLong; + +public class TrackedMemorySegmentLease implements Lease, Iterator { + private final Lease origin; + private final AtomicLong currentOffset; + + public TrackedMemorySegmentLease(final Lease origin) { + this(origin, new AtomicLong(0L)); + } + + public TrackedMemorySegmentLease(final Lease origin, final AtomicLong currentOffset) { + this.origin = origin; + this.currentOffset = currentOffset; + } + + @Override + public long id() { + return origin.id(); + } + + @Override + public long refs() { + return origin.refs(); + } + + @Override + public MemorySegment leasedObject() { + return origin.leasedObject(); + } + + @Override + public boolean hasZeroRefs() { + return origin.hasZeroRefs(); + } + + @Override + public Lease sliceAt(final long offset) { + return origin.sliceAt(offset); + } + + @Override + public boolean isStub() { + return origin.isStub(); + } + + @Override + public void close() throws Exception { + origin.close(); + } + + @Override + public boolean hasNext() { + return currentOffset.get() < origin.leasedObject().byteSize(); + } + + @Override + public Byte next() { + if (!hasNext()) { + throw new IndexOutOfBoundsException("Reached end of segment, cannot provide next byte"); + } + final long nextIndex = currentOffset.getAndIncrement(); + + return origin.leasedObject().get(ValueLayout.JAVA_BYTE, nextIndex); + } + + public long position() { + return currentOffset.get(); + } +} diff --git a/src/test/java/com/teragrep/net_01/channel/context/buffer/TrackedMemorySegmentLeaseTest.java b/src/test/java/com/teragrep/net_01/channel/context/buffer/TrackedMemorySegmentLeaseTest.java new file mode 100644 index 0000000..5aa6c73 --- /dev/null +++ b/src/test/java/com/teragrep/net_01/channel/context/buffer/TrackedMemorySegmentLeaseTest.java @@ -0,0 +1,36 @@ +package com.teragrep.net_01.channel.context.buffer; + +import com.teragrep.buf_01.buffer.lease.MemorySegmentLeaseStub; +import com.teragrep.buf_01.buffer.pool.OpeningPool; +import com.teragrep.buf_01.buffer.supply.ArenaMemorySegmentLeaseSupplier; +import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; +import com.teragrep.poj_01.pool.UnboundPool; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.lang.foreign.Arena; + +public final class TrackedMemorySegmentLeaseTest +{ + @Test + void testProgressing() { + final OpeningPool pool = new OpeningPool(new UnboundPool<>(new ArenaMemorySegmentLeaseSupplier(Arena.ofShared(), 5), new MemorySegmentLeaseStub())); + final TrackedMemorySegmentLease trackedLease = new TrackedMemorySegmentLease(pool.get()); + + Assertions.assertEquals(0L, trackedLease.position()); + + int loops = 0; + for (int i = 0; i < 5; i++) { + Assertions.assertEquals(i, trackedLease.position()); + Assertions.assertTrue(trackedLease.hasNext()); + Assertions.assertEquals((byte)0, trackedLease.next()); + loops++; + } + Assertions.assertEquals(5, loops); + + Assertions.assertFalse(trackedLease.hasNext()); + Assertions.assertThrows(IndexOutOfBoundsException.class, trackedLease::next); + Assertions.assertEquals(5L, trackedLease.position()); + } +} + From dca39ce6dc711ec278a6c4a0dfb3ebe596f98954 Mon Sep 17 00:00:00 2001 From: eemhu <125959687+eemhu@users.noreply.github.com> Date: Thu, 19 Mar 2026 10:39:34 +0200 Subject: [PATCH 04/45] pom.xml: JDK25 & poj_01, buf_01 dependencies --- pom.xml | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index 8aae18c..8af5ea9 100644 --- a/pom.xml +++ b/pom.xml @@ -29,17 +29,29 @@ -SNAPSHOT - 1.8 + 25 1.10.2 5.10.2 - 1.8 - 1.8 + 25 + 25 UTF-8 UTF-8 0.0.1 + 1.0.0 + 3.0.0 + + com.teragrep + buf_01 + ${teragrep.buf_01.version} + + + com.teragrep + poj_01 + ${teragrep.poj_01.version} + org.slf4j @@ -104,7 +116,7 @@ 3.2.5 - 1.8 + 25 @@ -253,7 +265,7 @@ jar - 8 + 25 From 20cdb0bffdd9769f28a8aefd6abdfcc6969d9e30 Mon Sep 17 00:00:00 2001 From: eemhu <125959687+eemhu@users.noreply.github.com> Date: Fri, 27 Mar 2026 10:46:41 +0200 Subject: [PATCH 05/45] serverTest & ingressimpl in progress --- .../net_01/channel/context/Clock.java | 3 +- .../net_01/channel/context/IngressImpl.java | 37 +++++++--- .../net_01/channel/context/ListenContext.java | 1 + .../teragrep/net_01/eventloop/EventLoop.java | 11 ++- .../teragrep/net_01/server/ServerFactory.java | 4 +- .../channel/context/ClockFactoryFake.java | 18 +++++ .../net_01/channel/context/ClockFake.java | 41 +++++++++++ .../net_01/channel/server/ServerTest.java | 73 +++++++++++++++++++ 8 files changed, 172 insertions(+), 16 deletions(-) create mode 100644 src/test/java/com/teragrep/net_01/channel/context/ClockFactoryFake.java create mode 100644 src/test/java/com/teragrep/net_01/channel/context/ClockFake.java create mode 100644 src/test/java/com/teragrep/net_01/channel/server/ServerTest.java diff --git a/src/main/java/com/teragrep/net_01/channel/context/Clock.java b/src/main/java/com/teragrep/net_01/channel/context/Clock.java index 76d1ca8..710c97a 100644 --- a/src/main/java/com/teragrep/net_01/channel/context/Clock.java +++ b/src/main/java/com/teragrep/net_01/channel/context/Clock.java @@ -46,6 +46,7 @@ package com.teragrep.net_01.channel.context; import com.teragrep.buf_01.buffer.lease.Lease; +import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; import java.lang.foreign.MemorySegment; @@ -55,5 +56,5 @@ public interface Clock extends AutoCloseable { * @param bufferLease to be consumed by the Clock. Clock or it's subsequent actions must close all BufferLease's it * receives otherwise encapsulated buffers are not reusable and memory allocator consumes time. */ - void advance(Lease bufferLease); + void advance(TrackedMemorySegmentLease bufferLease); } diff --git a/src/main/java/com/teragrep/net_01/channel/context/IngressImpl.java b/src/main/java/com/teragrep/net_01/channel/context/IngressImpl.java index 4feb360..3dc7a03 100644 --- a/src/main/java/com/teragrep/net_01/channel/context/IngressImpl.java +++ b/src/main/java/com/teragrep/net_01/channel/context/IngressImpl.java @@ -45,6 +45,7 @@ */ package com.teragrep.net_01.channel.context; +import com.teragrep.buf_01.buffer.lease.MemorySegmentLease; import com.teragrep.buf_01.buffer.lease.OpenableLease; import com.teragrep.buf_01.buffer.pool.LeaseMultiGet; import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; @@ -58,9 +59,12 @@ import java.lang.foreign.MemorySegment; import java.nio.ByteBuffer; import java.nio.channels.CancelledKeyException; +import java.util.Collections; import java.util.LinkedList; import java.util.List; +import java.util.concurrent.ConcurrentLinkedDeque; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; @@ -73,7 +77,7 @@ final class IngressImpl implements Ingress { private final EstablishedContextImpl establishedContext; private final Pool> memorySegmentLeasePool; - private final LinkedList activeBuffers; + private final List activeBuffers; private final Lock lock; // tls public final AtomicBoolean needWrite; @@ -84,11 +88,11 @@ final class IngressImpl implements Ingress { this.establishedContext = establishedContext; this.memorySegmentLeasePool = memorySegmentLeasePool; - this.activeBuffers = new LinkedList<>(); + this.activeBuffers = Collections.synchronizedList(new LinkedList<>()); this.lock = new ReentrantLock(); this.needWrite = new AtomicBoolean(); - this.interestedClocks = new LinkedList<>(); + this.interestedClocks = Collections.synchronizedList(new LinkedList<>()); } @Override @@ -106,10 +110,12 @@ public void run() { long readBytes = readData(); if (!isDataAvailable(readBytes)) { + System.out.println("No data available"); break; } boolean continueReading = true; + System.out.println("activeBuffers.isEmpty=" + activeBuffers.isEmpty()); while (!activeBuffers.isEmpty()) { // IMPORTANT: current tls implementation will skip bytes if BufferLeases are not fully consumed. TrackedMemorySegmentLease bufferLease = activeBuffers.removeFirst(); @@ -133,8 +139,9 @@ public void run() { if (bufferLease.hasNext()) { // return back as it has some remaining + System.out.println("something remaining"); LOGGER.debug("pushBack bufferLease id <{}>", bufferLease.id()); - activeBuffers.push(bufferLease); + activeBuffers.add(bufferLease); if (LOGGER.isDebugEnabled()) { LOGGER .debug( @@ -240,12 +247,24 @@ private long readData() throws IOException { ByteBuffer[] byteBufferArray = byteBufferList.toArray(new ByteBuffer[0]); readBytes = establishedContext.socket().read(byteBufferArray); - // TODO: Figure out a way to see which buffers were written into. - // Right now, buffers that are not written into are pushed into activeBuffers. + System.out.println("readBytes = " + readBytes); + long bytesLeft = readBytes; + boolean allRead = false; + for (final OpenableLease bufferLease : bufferLeases) { + final long byteSize = bufferLease.leasedObject().byteSize(); - for (final OpenableLease bufferLease : bufferLeases) { - activeBuffers.push(new TrackedMemorySegmentLease(bufferLease)); - } + if (!allRead) { + activeBuffers.add(new TrackedMemorySegmentLease(bufferLease, new AtomicLong(Math.min(bytesLeft, byteSize)))); + } + + bytesLeft -= byteSize; + + if (bytesLeft <= 0) { + allRead = true; + } + } + + System.out.println("buffers.size=" + activeBuffers.size()); LOGGER.debug("establishedContext.read got <{}> bytes from socket", readBytes); diff --git a/src/main/java/com/teragrep/net_01/channel/context/ListenContext.java b/src/main/java/com/teragrep/net_01/channel/context/ListenContext.java index 50c020e..6a018cb 100644 --- a/src/main/java/com/teragrep/net_01/channel/context/ListenContext.java +++ b/src/main/java/com/teragrep/net_01/channel/context/ListenContext.java @@ -85,6 +85,7 @@ public final class ListenContext implements Context { @Override public void handleEvent(SelectionKey selectionKey) { + System.out.println("handling event: " + selectionKey); try { if (selectionKey.isAcceptable()) { // create the client socket for a newly received connection diff --git a/src/main/java/com/teragrep/net_01/eventloop/EventLoop.java b/src/main/java/com/teragrep/net_01/eventloop/EventLoop.java index 988cb3d..1f58e6b 100644 --- a/src/main/java/com/teragrep/net_01/eventloop/EventLoop.java +++ b/src/main/java/com/teragrep/net_01/eventloop/EventLoop.java @@ -87,11 +87,13 @@ public final class EventLoop implements AutoCloseable, Runnable { * @param context to register */ public void register(Context context) { + LOGGER.info("EventLoop.Register: {}", context); pendingContextRegistrations.add(context); wakeup(); } private void registerPendingRegistrations() { + LOGGER.info("register pending regs"); while (true) { Context context = pendingContextRegistrations.poll(); if (context != null) { @@ -120,10 +122,10 @@ public void poll() throws IOException { registerPendingRegistrations(); - LOGGER.debug("readyKeys <{}>", readyKeys); + LOGGER.info("readyKeys <{}>", readyKeys); Set selectionKeys = selector.selectedKeys(); - LOGGER.debug("selectionKeys <{}> ", selectionKeys); + LOGGER.info("selectionKeys <{}> ", selectionKeys); for (SelectionKey selectionKey : selectionKeys) { try { if (LOGGER.isDebugEnabled()) { @@ -193,8 +195,9 @@ public void wakeup() { @Override public void run() { try { - LOGGER.debug("Started"); + LOGGER.info("Started"); while (!stop.get()) { + System.out.println("polling " + Thread.currentThread().getName()); poll(); } } @@ -204,7 +207,7 @@ public void run() { finally { close(); } - LOGGER.debug("Stopped"); + LOGGER.info("Stopped"); } public void stop() { diff --git a/src/main/java/com/teragrep/net_01/server/ServerFactory.java b/src/main/java/com/teragrep/net_01/server/ServerFactory.java index 74e7672..5f5cabb 100644 --- a/src/main/java/com/teragrep/net_01/server/ServerFactory.java +++ b/src/main/java/com/teragrep/net_01/server/ServerFactory.java @@ -98,9 +98,9 @@ public Server create(int port) throws IOException { ); ListenContext listenContext = listenContextFactory.open(new InetSocketAddress(port)); - LOGGER.debug("registering to eventLoop <{}>", eventLoop); + LOGGER.info("registering to eventLoop <{}>", eventLoop); eventLoop.register(listenContext); - LOGGER.debug("registered to eventLoop <{}>", eventLoop); + LOGGER.info("registered to eventLoop <{}>", eventLoop); return new Server(listenContext); } } diff --git a/src/test/java/com/teragrep/net_01/channel/context/ClockFactoryFake.java b/src/test/java/com/teragrep/net_01/channel/context/ClockFactoryFake.java new file mode 100644 index 0000000..cdd6426 --- /dev/null +++ b/src/test/java/com/teragrep/net_01/channel/context/ClockFactoryFake.java @@ -0,0 +1,18 @@ +package com.teragrep.net_01.channel.context; + +import java.util.List; +import java.util.function.Consumer; + +public final class ClockFactoryFake implements ClockFactory{ + + private final Consumer> messageConsumer; + + public ClockFactoryFake(Consumer> messageConsumer){ + this.messageConsumer = messageConsumer; + } + + @Override + public Clock create(final EstablishedContext establishedContext) { + return new ClockFake(establishedContext, messageConsumer); + } +} diff --git a/src/test/java/com/teragrep/net_01/channel/context/ClockFake.java b/src/test/java/com/teragrep/net_01/channel/context/ClockFake.java new file mode 100644 index 0000000..bbcc884 --- /dev/null +++ b/src/test/java/com/teragrep/net_01/channel/context/ClockFake.java @@ -0,0 +1,41 @@ +package com.teragrep.net_01.channel.context; + +import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; + +import java.lang.foreign.ValueLayout; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +public final class ClockFake implements Clock { + private final EstablishedContext ctx; + private final Consumer> messageConsumer; + + public ClockFake(final EstablishedContext ctx, final Consumer> messageConsumer) { + this.ctx = ctx; + this.messageConsumer = messageConsumer; + } + + @Override + public void advance(TrackedMemorySegmentLease lease) { + System.out.println("advancing clock @" + Thread.currentThread().getName()); + System.out.println("pos=" + lease.position()); + + System.out.println(lease.leasedObject().get(ValueLayout.JAVA_BYTE, 0)); + + final List bytes = new ArrayList<>(); + while (lease.hasNext()) { + final byte b = lease.next(); + if (b != 0){ + bytes.add(b); + } + } + + messageConsumer.accept(bytes); + } + + @Override + public void close() throws Exception { + // no-op + } +} diff --git a/src/test/java/com/teragrep/net_01/channel/server/ServerTest.java b/src/test/java/com/teragrep/net_01/channel/server/ServerTest.java new file mode 100644 index 0000000..8bd7332 --- /dev/null +++ b/src/test/java/com/teragrep/net_01/channel/server/ServerTest.java @@ -0,0 +1,73 @@ +package com.teragrep.net_01.channel.server; + +import com.teragrep.net_01.channel.context.ClockFactory; +import com.teragrep.net_01.channel.context.ClockFactoryFake; +import com.teragrep.net_01.channel.socket.PlainFactory; +import com.teragrep.net_01.channel.socket.Socket; +import com.teragrep.net_01.channel.socket.SocketFactory; +import com.teragrep.net_01.eventloop.EventLoop; +import com.teragrep.net_01.eventloop.EventLoopFactory; +import com.teragrep.net_01.server.Server; +import com.teragrep.net_01.server.ServerFactory; +import org.junit.jupiter.api.*; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.Executors; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public final class ServerTest { + private Server server; + private final List> messages = new ArrayList<>(); + @BeforeAll + void beforeAll() { + final EventLoopFactory eventLoopFactory = new EventLoopFactory(); + final SocketFactory socketFactory = new PlainFactory(); + final ClockFactory clockFactory = new ClockFactoryFake(messages::add); + + final EventLoop el = Assertions.assertDoesNotThrow(eventLoopFactory::create); + + // eventLoopThread must run, otherwise nothing will be processed + final Thread elT = new Thread(el); + elT.start(); + + final ServerFactory serverFactory = new ServerFactory(el, + Executors.newSingleThreadExecutor(), socketFactory, clockFactory); + + this.server = Assertions.assertDoesNotThrow(() -> serverFactory.create(9090)); + } + + @AfterAll + void afterAll() { + Assertions.assertDoesNotThrow(this.server::close); + } + + @BeforeEach + void beforeEach() { + messages.clear(); + } + + @Test + void test() throws Exception{ + final java.net.Socket clientSocket = Assertions.assertDoesNotThrow(() -> new java.net.Socket("localhost", 9090)); + + final PrintWriter out = new PrintWriter(Assertions.assertDoesNotThrow(clientSocket::getOutputStream), true); + final BufferedReader in = new BufferedReader(new InputStreamReader(Assertions.assertDoesNotThrow(clientSocket::getInputStream))); + + out.println("aaaa"); + out.flush(); + + Thread.sleep(500); + + Assertions.assertEquals(1, messages.size()); + Assertions.assertEquals(List.of((byte) 'a'), messages.getFirst()); + + Assertions.assertDoesNotThrow(in::close); + Assertions.assertDoesNotThrow(out::close); + Assertions.assertDoesNotThrow(clientSocket::close); + } +} From fc10bd4582b66e9a2732bc6dd6348690f7631d50 Mon Sep 17 00:00:00 2001 From: eemhu <125959687+eemhu@users.noreply.github.com> Date: Fri, 27 Mar 2026 12:08:26 +0200 Subject: [PATCH 06/45] finally working serverTest --- .../java/com/teragrep/net_01/channel/context/IngressImpl.java | 3 ++- .../java/com/teragrep/net_01/channel/context/ClockFake.java | 2 -- .../java/com/teragrep/net_01/channel/server/ServerTest.java | 4 ++-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/teragrep/net_01/channel/context/IngressImpl.java b/src/main/java/com/teragrep/net_01/channel/context/IngressImpl.java index 3dc7a03..481e3b0 100644 --- a/src/main/java/com/teragrep/net_01/channel/context/IngressImpl.java +++ b/src/main/java/com/teragrep/net_01/channel/context/IngressImpl.java @@ -254,7 +254,8 @@ private long readData() throws IOException { final long byteSize = bufferLease.leasedObject().byteSize(); if (!allRead) { - activeBuffers.add(new TrackedMemorySegmentLease(bufferLease, new AtomicLong(Math.min(bytesLeft, byteSize)))); + // same as ByteBuffer.flip() + activeBuffers.add(new TrackedMemorySegmentLease(bufferLease)); } bytesLeft -= byteSize; diff --git a/src/test/java/com/teragrep/net_01/channel/context/ClockFake.java b/src/test/java/com/teragrep/net_01/channel/context/ClockFake.java index bbcc884..43ffa61 100644 --- a/src/test/java/com/teragrep/net_01/channel/context/ClockFake.java +++ b/src/test/java/com/teragrep/net_01/channel/context/ClockFake.java @@ -21,8 +21,6 @@ public void advance(TrackedMemorySegmentLease lease) { System.out.println("advancing clock @" + Thread.currentThread().getName()); System.out.println("pos=" + lease.position()); - System.out.println(lease.leasedObject().get(ValueLayout.JAVA_BYTE, 0)); - final List bytes = new ArrayList<>(); while (lease.hasNext()) { final byte b = lease.next(); diff --git a/src/test/java/com/teragrep/net_01/channel/server/ServerTest.java b/src/test/java/com/teragrep/net_01/channel/server/ServerTest.java index 8bd7332..929da9e 100644 --- a/src/test/java/com/teragrep/net_01/channel/server/ServerTest.java +++ b/src/test/java/com/teragrep/net_01/channel/server/ServerTest.java @@ -18,6 +18,7 @@ import java.util.Arrays; import java.util.List; import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicLong; @TestInstance(TestInstance.Lifecycle.PER_CLASS) public final class ServerTest { @@ -58,12 +59,11 @@ void test() throws Exception{ final PrintWriter out = new PrintWriter(Assertions.assertDoesNotThrow(clientSocket::getOutputStream), true); final BufferedReader in = new BufferedReader(new InputStreamReader(Assertions.assertDoesNotThrow(clientSocket::getInputStream))); - out.println("aaaa"); + out.print("a"); out.flush(); Thread.sleep(500); - Assertions.assertEquals(1, messages.size()); Assertions.assertEquals(List.of((byte) 'a'), messages.getFirst()); Assertions.assertDoesNotThrow(in::close); From 684adfa78e1c125b7f8a0e491509f686da266173 Mon Sep 17 00:00:00 2001 From: eemhu <125959687+eemhu@users.noreply.github.com> Date: Fri, 27 Mar 2026 12:41:01 +0200 Subject: [PATCH 07/45] replace thread.sleep with countDownLatch in ServerTest. --- .../net_01/channel/server/ServerTest.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/test/java/com/teragrep/net_01/channel/server/ServerTest.java b/src/test/java/com/teragrep/net_01/channel/server/ServerTest.java index 929da9e..9397ab2 100644 --- a/src/test/java/com/teragrep/net_01/channel/server/ServerTest.java +++ b/src/test/java/com/teragrep/net_01/channel/server/ServerTest.java @@ -15,20 +15,24 @@ import java.io.InputStreamReader; import java.io.PrintWriter; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executors; -import java.util.concurrent.atomic.AtomicLong; @TestInstance(TestInstance.Lifecycle.PER_CLASS) public final class ServerTest { private Server server; + private CountDownLatch countDownLatch; private final List> messages = new ArrayList<>(); + @BeforeAll void beforeAll() { final EventLoopFactory eventLoopFactory = new EventLoopFactory(); final SocketFactory socketFactory = new PlainFactory(); - final ClockFactory clockFactory = new ClockFactoryFake(messages::add); + final ClockFactory clockFactory = new ClockFactoryFake((msg -> { + messages.add(msg); + countDownLatch.countDown(); + })); final EventLoop el = Assertions.assertDoesNotThrow(eventLoopFactory::create); @@ -53,7 +57,8 @@ void beforeEach() { } @Test - void test() throws Exception{ + void testReceivingOneMessage() { + this.countDownLatch = new CountDownLatch(1); final java.net.Socket clientSocket = Assertions.assertDoesNotThrow(() -> new java.net.Socket("localhost", 9090)); final PrintWriter out = new PrintWriter(Assertions.assertDoesNotThrow(clientSocket::getOutputStream), true); @@ -62,7 +67,7 @@ void test() throws Exception{ out.print("a"); out.flush(); - Thread.sleep(500); + Assertions.assertDoesNotThrow(() -> countDownLatch.await()); Assertions.assertEquals(List.of((byte) 'a'), messages.getFirst()); From ae3b4792bf9fe46c3171d23c4613802fe254dfe7 Mon Sep 17 00:00:00 2001 From: eemhu <125959687+eemhu@users.noreply.github.com> Date: Fri, 27 Mar 2026 13:20:33 +0200 Subject: [PATCH 08/45] test one and three chars --- .../net_01/channel/server/ServerTest.java | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/test/java/com/teragrep/net_01/channel/server/ServerTest.java b/src/test/java/com/teragrep/net_01/channel/server/ServerTest.java index 9397ab2..3bdb0ff 100644 --- a/src/test/java/com/teragrep/net_01/channel/server/ServerTest.java +++ b/src/test/java/com/teragrep/net_01/channel/server/ServerTest.java @@ -57,7 +57,7 @@ void beforeEach() { } @Test - void testReceivingOneMessage() { + void testReceivingOneChar() { this.countDownLatch = new CountDownLatch(1); final java.net.Socket clientSocket = Assertions.assertDoesNotThrow(() -> new java.net.Socket("localhost", 9090)); @@ -75,4 +75,28 @@ void testReceivingOneMessage() { Assertions.assertDoesNotThrow(out::close); Assertions.assertDoesNotThrow(clientSocket::close); } + + @Test + void testReceivingThreeChars() { + this.countDownLatch = new CountDownLatch(1); + final java.net.Socket clientSocket = Assertions.assertDoesNotThrow(() -> new java.net.Socket("localhost", 9090)); + + final PrintWriter out = new PrintWriter(Assertions.assertDoesNotThrow(clientSocket::getOutputStream), true); + final BufferedReader in = new BufferedReader(new InputStreamReader(Assertions.assertDoesNotThrow(clientSocket::getInputStream))); + + out.print("a"); + out.flush(); + out.print("b"); + out.flush(); + out.print("c"); + out.flush(); + + Assertions.assertDoesNotThrow(() -> countDownLatch.await()); + + Assertions.assertEquals(List.of((byte) 'a', (byte) 'b', (byte) 'c'), messages.getFirst()); + + Assertions.assertDoesNotThrow(in::close); + Assertions.assertDoesNotThrow(out::close); + Assertions.assertDoesNotThrow(clientSocket::close); + } } From e1d32584e861e57cbb9cc4bd8c021448c1d8ce87 Mon Sep 17 00:00:00 2001 From: eemhu <125959687+eemhu@users.noreply.github.com> Date: Fri, 27 Mar 2026 13:29:33 +0200 Subject: [PATCH 09/45] Change ServerTest beforeEach to afterEach as it makes more sense. --- .../java/com/teragrep/net_01/channel/server/ServerTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/com/teragrep/net_01/channel/server/ServerTest.java b/src/test/java/com/teragrep/net_01/channel/server/ServerTest.java index 3bdb0ff..464acfd 100644 --- a/src/test/java/com/teragrep/net_01/channel/server/ServerTest.java +++ b/src/test/java/com/teragrep/net_01/channel/server/ServerTest.java @@ -51,8 +51,8 @@ void afterAll() { Assertions.assertDoesNotThrow(this.server::close); } - @BeforeEach - void beforeEach() { + @AfterEach + void afterEach() { messages.clear(); } From ac78167c964d9bd077b75c9f819565b39d0abf46 Mon Sep 17 00:00:00 2001 From: eemhu <125959687+eemhu@users.noreply.github.com> Date: Fri, 27 Mar 2026 15:02:24 +0200 Subject: [PATCH 10/45] add SocketTest --- .../net_01/channel/socket/SocketTest.java | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 src/test/java/com/teragrep/net_01/channel/socket/SocketTest.java diff --git a/src/test/java/com/teragrep/net_01/channel/socket/SocketTest.java b/src/test/java/com/teragrep/net_01/channel/socket/SocketTest.java new file mode 100644 index 0000000..81da7bb --- /dev/null +++ b/src/test/java/com/teragrep/net_01/channel/socket/SocketTest.java @@ -0,0 +1,31 @@ +package com.teragrep.net_01.channel.socket; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; + +import java.net.InetSocketAddress; +import java.nio.channels.ServerSocketChannel; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public final class SocketTest { + + @Test + void testPlainSocketConnection() { + Assertions.assertDoesNotThrow(() -> { + // Create ServerSocketChannel and bind it to port=9090 + ServerSocketChannel socketCh = ServerSocketChannel.open(); + socketCh.bind(new InetSocketAddress(9090)); + + // Init client + java.net.Socket clientSocket = new java.net.Socket("localhost", 9090); + + // Init PlainSocket + Socket socket = new PlainSocket(socketCh.accept()); + + clientSocket.close(); + socketCh.close(); + socket.close(); + }); + } +} From a568e33d53f6130a178e555b2e47866474224a2d Mon Sep 17 00:00:00 2001 From: eemhu <125959687+eemhu@users.noreply.github.com> Date: Fri, 27 Mar 2026 15:51:02 +0200 Subject: [PATCH 11/45] add SocketTest read/write test --- .../net_01/channel/socket/SocketTest.java | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/src/test/java/com/teragrep/net_01/channel/socket/SocketTest.java b/src/test/java/com/teragrep/net_01/channel/socket/SocketTest.java index 81da7bb..0efb952 100644 --- a/src/test/java/com/teragrep/net_01/channel/socket/SocketTest.java +++ b/src/test/java/com/teragrep/net_01/channel/socket/SocketTest.java @@ -4,8 +4,13 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.PrintWriter; import java.net.InetSocketAddress; +import java.nio.ByteBuffer; import java.nio.channels.ServerSocketChannel; +import java.nio.charset.StandardCharsets; @TestInstance(TestInstance.Lifecycle.PER_CLASS) public final class SocketTest { @@ -28,4 +33,88 @@ void testPlainSocketConnection() { socket.close(); }); } + + @Test + void testPlainSocketWrite() { + Assertions.assertDoesNotThrow(() -> { + // Create ServerSocketChannel and bind it to port=9090 + ServerSocketChannel socketCh = ServerSocketChannel.open(); + socketCh.bind(new InetSocketAddress(9090)); + + // Init client + java.net.Socket clientSocket = new java.net.Socket("localhost", 9090); + final BufferedReader in = new BufferedReader(new InputStreamReader(Assertions.assertDoesNotThrow(clientSocket::getInputStream))); + + // Init PlainSocket + Socket socket = new PlainSocket(socketCh.accept()); + + socket.write(stringToBuffer("helloWorld\n")); + + final String readLine = in.readLine(); + + Assertions.assertEquals("helloWorld", readLine); + + clientSocket.close(); + socketCh.close(); + socket.close(); + }); + } + + @Test + void testPlainSocketRead() { + Assertions.assertDoesNotThrow(() -> { + // Create ServerSocketChannel and bind it to port=9090 + ServerSocketChannel socketCh = ServerSocketChannel.open(); + socketCh.bind(new InetSocketAddress(9090)); + + // Init client + java.net.Socket clientSocket = new java.net.Socket("localhost", 9090); + final PrintWriter out = new PrintWriter(Assertions.assertDoesNotThrow(clientSocket::getOutputStream), true); + + // Init PlainSocket + Socket socket = new PlainSocket(socketCh.accept()); + + out.println("worldHello"); + + ByteBuffer[] bufs = emptyBuffers(1, 10); + socket.read(bufs); + + Assertions.assertEquals("worldHello", bufferToString(bufs)); + + clientSocket.close(); + socketCh.close(); + socket.close(); + }); + } + + private String bufferToString(final ByteBuffer[] bufs) { + final StringBuilder stringBuilder = new StringBuilder(); + for (final ByteBuffer buf : bufs) { + buf.flip(); + while (buf.hasRemaining()) { + stringBuilder.append((char) buf.get()); + } + buf.flip(); + } + return stringBuilder.toString(); + } + + private ByteBuffer[] stringToBuffer(final String str) { + final ByteBuffer[] arr = new ByteBuffer[1]; + + final byte[] bytes = str.getBytes(StandardCharsets.UTF_8); + arr[0] = ByteBuffer.wrap(bytes); + + return arr; + } + + private ByteBuffer[] emptyBuffers(int n, int bytesEach) { + final ByteBuffer[] arr = new ByteBuffer[n]; + + for (int i = 0; i < n; i++) { + arr[i] = ByteBuffer.allocate(bytesEach); + } + + return arr; + } } From 05338dea984225fa7cbec50f015ac3932e1e9b82 Mon Sep 17 00:00:00 2001 From: eemhu <125959687+eemhu@users.noreply.github.com> Date: Fri, 27 Mar 2026 15:56:14 +0200 Subject: [PATCH 12/45] socketTest variables to final --- .../teragrep/net_01/channel/socket/SocketTest.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/test/java/com/teragrep/net_01/channel/socket/SocketTest.java b/src/test/java/com/teragrep/net_01/channel/socket/SocketTest.java index 0efb952..5371825 100644 --- a/src/test/java/com/teragrep/net_01/channel/socket/SocketTest.java +++ b/src/test/java/com/teragrep/net_01/channel/socket/SocketTest.java @@ -19,14 +19,14 @@ public final class SocketTest { void testPlainSocketConnection() { Assertions.assertDoesNotThrow(() -> { // Create ServerSocketChannel and bind it to port=9090 - ServerSocketChannel socketCh = ServerSocketChannel.open(); + final ServerSocketChannel socketCh = ServerSocketChannel.open(); socketCh.bind(new InetSocketAddress(9090)); // Init client - java.net.Socket clientSocket = new java.net.Socket("localhost", 9090); + final java.net.Socket clientSocket = new java.net.Socket("localhost", 9090); // Init PlainSocket - Socket socket = new PlainSocket(socketCh.accept()); + final Socket socket = new PlainSocket(socketCh.accept()); clientSocket.close(); socketCh.close(); @@ -38,15 +38,15 @@ void testPlainSocketConnection() { void testPlainSocketWrite() { Assertions.assertDoesNotThrow(() -> { // Create ServerSocketChannel and bind it to port=9090 - ServerSocketChannel socketCh = ServerSocketChannel.open(); + final ServerSocketChannel socketCh = ServerSocketChannel.open(); socketCh.bind(new InetSocketAddress(9090)); // Init client - java.net.Socket clientSocket = new java.net.Socket("localhost", 9090); + final java.net.Socket clientSocket = new java.net.Socket("localhost", 9090); final BufferedReader in = new BufferedReader(new InputStreamReader(Assertions.assertDoesNotThrow(clientSocket::getInputStream))); // Init PlainSocket - Socket socket = new PlainSocket(socketCh.accept()); + final Socket socket = new PlainSocket(socketCh.accept()); socket.write(stringToBuffer("helloWorld\n")); From 381ad14e76e2b8f26c08f49f7dd2a749c99da02e Mon Sep 17 00:00:00 2001 From: eemhu <125959687+eemhu@users.noreply.github.com> Date: Mon, 30 Mar 2026 10:51:45 +0300 Subject: [PATCH 13/45] add limit type functionality to TrackedMemorySegmentLease and IngressImpl. --- .../buffer/TrackedMemorySegmentLease.java | 22 +++++++++++++++++-- .../net_01/channel/context/IngressImpl.java | 14 ++++++++++-- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/teragrep/net_01/channel/buffer/TrackedMemorySegmentLease.java b/src/main/java/com/teragrep/net_01/channel/buffer/TrackedMemorySegmentLease.java index b66d9fb..6ab14b2 100644 --- a/src/main/java/com/teragrep/net_01/channel/buffer/TrackedMemorySegmentLease.java +++ b/src/main/java/com/teragrep/net_01/channel/buffer/TrackedMemorySegmentLease.java @@ -10,14 +10,20 @@ public class TrackedMemorySegmentLease implements Lease, Iterator { private final Lease origin; private final AtomicLong currentOffset; + private final AtomicLong limit; public TrackedMemorySegmentLease(final Lease origin) { this(origin, new AtomicLong(0L)); } public TrackedMemorySegmentLease(final Lease origin, final AtomicLong currentOffset) { + this(origin, currentOffset, new AtomicLong(-1L)); + } + + public TrackedMemorySegmentLease(final Lease origin, final AtomicLong currentOffset, final AtomicLong limit) { this.origin = origin; this.currentOffset = currentOffset; + this.limit = limit; } @Override @@ -57,13 +63,21 @@ public void close() throws Exception { @Override public boolean hasNext() { - return currentOffset.get() < origin.leasedObject().byteSize(); + final boolean rv; + if (limit.get() == -1) { + // limit not set, ignore + rv = currentOffset.get() < origin.leasedObject().byteSize(); + } + else { + rv = currentOffset.get() < Math.min(limit.get(), origin.leasedObject().byteSize()); + } + return rv; } @Override public Byte next() { if (!hasNext()) { - throw new IndexOutOfBoundsException("Reached end of segment, cannot provide next byte"); + throw new IndexOutOfBoundsException("Reached end of segment or limit, cannot provide next byte"); } final long nextIndex = currentOffset.getAndIncrement(); @@ -73,4 +87,8 @@ public Byte next() { public long position() { return currentOffset.get(); } + + public long limit() { + return limit.get(); + } } diff --git a/src/main/java/com/teragrep/net_01/channel/context/IngressImpl.java b/src/main/java/com/teragrep/net_01/channel/context/IngressImpl.java index 481e3b0..2786965 100644 --- a/src/main/java/com/teragrep/net_01/channel/context/IngressImpl.java +++ b/src/main/java/com/teragrep/net_01/channel/context/IngressImpl.java @@ -253,9 +253,19 @@ private long readData() throws IOException { for (final OpenableLease bufferLease : bufferLeases) { final long byteSize = bufferLease.leasedObject().byteSize(); - if (!allRead) { + if (!allRead && readBytes > 0) { // same as ByteBuffer.flip() - activeBuffers.add(new TrackedMemorySegmentLease(bufferLease)); + final long diff = bytesLeft - byteSize; + if (diff < 0) { + // mem.segment bigger than bytes left. + // set limit to read amount. + final long limit = byteSize - Math.abs(diff); + activeBuffers.add(new TrackedMemorySegmentLease(bufferLease, new AtomicLong(0L), new AtomicLong(limit))); + } + else { + //else: full mem.segment used, no need to set limit. + activeBuffers.add(new TrackedMemorySegmentLease(bufferLease)); + } } bytesLeft -= byteSize; From 0eee7c705b1cab945f787dc4f5a46f8e81b345e7 Mon Sep 17 00:00:00 2001 From: eemhu <125959687+eemhu@users.noreply.github.com> Date: Mon, 30 Mar 2026 12:57:49 +0300 Subject: [PATCH 14/45] remove unnecessary code from ServerTest.testReceivingOneChar --- src/test/java/com/teragrep/net_01/channel/server/ServerTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/java/com/teragrep/net_01/channel/server/ServerTest.java b/src/test/java/com/teragrep/net_01/channel/server/ServerTest.java index 464acfd..26132ca 100644 --- a/src/test/java/com/teragrep/net_01/channel/server/ServerTest.java +++ b/src/test/java/com/teragrep/net_01/channel/server/ServerTest.java @@ -3,7 +3,6 @@ import com.teragrep.net_01.channel.context.ClockFactory; import com.teragrep.net_01.channel.context.ClockFactoryFake; import com.teragrep.net_01.channel.socket.PlainFactory; -import com.teragrep.net_01.channel.socket.Socket; import com.teragrep.net_01.channel.socket.SocketFactory; import com.teragrep.net_01.eventloop.EventLoop; import com.teragrep.net_01.eventloop.EventLoopFactory; From 7fe62ca47eca266e50d0efc79c64c13f33a9e558 Mon Sep 17 00:00:00 2001 From: eemhu <125959687+eemhu@users.noreply.github.com> Date: Mon, 30 Mar 2026 13:23:29 +0300 Subject: [PATCH 15/45] rename Clock fakes to ConsumingClock, cleanup --- .../{ClockFake.java => ConsumingClock.java} | 13 ++----- ...ryFake.java => ConsumingClockFactory.java} | 6 ++-- .../net_01/channel/server/ServerTest.java | 34 +++++++++++++++++-- 3 files changed, 38 insertions(+), 15 deletions(-) rename src/test/java/com/teragrep/net_01/channel/context/{ClockFake.java => ConsumingClock.java} (61%) rename src/test/java/com/teragrep/net_01/channel/context/{ClockFactoryFake.java => ConsumingClockFactory.java} (59%) diff --git a/src/test/java/com/teragrep/net_01/channel/context/ClockFake.java b/src/test/java/com/teragrep/net_01/channel/context/ConsumingClock.java similarity index 61% rename from src/test/java/com/teragrep/net_01/channel/context/ClockFake.java rename to src/test/java/com/teragrep/net_01/channel/context/ConsumingClock.java index 43ffa61..1bec299 100644 --- a/src/test/java/com/teragrep/net_01/channel/context/ClockFake.java +++ b/src/test/java/com/teragrep/net_01/channel/context/ConsumingClock.java @@ -2,31 +2,24 @@ import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; -import java.lang.foreign.ValueLayout; import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; -public final class ClockFake implements Clock { +public final class ConsumingClock implements Clock { private final EstablishedContext ctx; private final Consumer> messageConsumer; - public ClockFake(final EstablishedContext ctx, final Consumer> messageConsumer) { + public ConsumingClock(final EstablishedContext ctx, final Consumer> messageConsumer) { this.ctx = ctx; this.messageConsumer = messageConsumer; } @Override public void advance(TrackedMemorySegmentLease lease) { - System.out.println("advancing clock @" + Thread.currentThread().getName()); - System.out.println("pos=" + lease.position()); - final List bytes = new ArrayList<>(); while (lease.hasNext()) { - final byte b = lease.next(); - if (b != 0){ - bytes.add(b); - } + bytes.add(lease.next()); } messageConsumer.accept(bytes); diff --git a/src/test/java/com/teragrep/net_01/channel/context/ClockFactoryFake.java b/src/test/java/com/teragrep/net_01/channel/context/ConsumingClockFactory.java similarity index 59% rename from src/test/java/com/teragrep/net_01/channel/context/ClockFactoryFake.java rename to src/test/java/com/teragrep/net_01/channel/context/ConsumingClockFactory.java index cdd6426..0f6ae32 100644 --- a/src/test/java/com/teragrep/net_01/channel/context/ClockFactoryFake.java +++ b/src/test/java/com/teragrep/net_01/channel/context/ConsumingClockFactory.java @@ -3,16 +3,16 @@ import java.util.List; import java.util.function.Consumer; -public final class ClockFactoryFake implements ClockFactory{ +public final class ConsumingClockFactory implements ClockFactory { private final Consumer> messageConsumer; - public ClockFactoryFake(Consumer> messageConsumer){ + public ConsumingClockFactory(Consumer> messageConsumer){ this.messageConsumer = messageConsumer; } @Override public Clock create(final EstablishedContext establishedContext) { - return new ClockFake(establishedContext, messageConsumer); + return new ConsumingClock(establishedContext, messageConsumer); } } diff --git a/src/test/java/com/teragrep/net_01/channel/server/ServerTest.java b/src/test/java/com/teragrep/net_01/channel/server/ServerTest.java index 26132ca..1f720fb 100644 --- a/src/test/java/com/teragrep/net_01/channel/server/ServerTest.java +++ b/src/test/java/com/teragrep/net_01/channel/server/ServerTest.java @@ -1,7 +1,7 @@ package com.teragrep.net_01.channel.server; import com.teragrep.net_01.channel.context.ClockFactory; -import com.teragrep.net_01.channel.context.ClockFactoryFake; +import com.teragrep.net_01.channel.context.ConsumingClockFactory; import com.teragrep.net_01.channel.socket.PlainFactory; import com.teragrep.net_01.channel.socket.SocketFactory; import com.teragrep.net_01.eventloop.EventLoop; @@ -28,7 +28,7 @@ public final class ServerTest { void beforeAll() { final EventLoopFactory eventLoopFactory = new EventLoopFactory(); final SocketFactory socketFactory = new PlainFactory(); - final ClockFactory clockFactory = new ClockFactoryFake((msg -> { + final ClockFactory clockFactory = new ConsumingClockFactory((msg -> { messages.add(msg); countDownLatch.countDown(); })); @@ -94,6 +94,36 @@ void testReceivingThreeChars() { Assertions.assertEquals(List.of((byte) 'a', (byte) 'b', (byte) 'c'), messages.getFirst()); + Assertions.assertDoesNotThrow(in::close); + Assertions.assertDoesNotThrow(out::close); + Assertions.assertDoesNotThrow(clientSocket::close); + } + + @Test + void testSending() { + this.countDownLatch = new CountDownLatch(1); + final java.net.Socket clientSocket = Assertions.assertDoesNotThrow(() -> new java.net.Socket("localhost", 9090)); + + final PrintWriter out = new PrintWriter(Assertions.assertDoesNotThrow(clientSocket::getOutputStream), true); + final BufferedReader in = new BufferedReader(new InputStreamReader(Assertions.assertDoesNotThrow(clientSocket::getInputStream))); + + out.print("a"); + out.flush(); + out.print("b"); + out.flush(); + out.print("c"); + out.flush(); + + Assertions.assertDoesNotThrow(() -> countDownLatch.await()); + + Assertions.assertEquals(List.of((byte) 'a', (byte) 'b', (byte) 'c'), messages.getFirst()); + + String x; + while ((x = Assertions.assertDoesNotThrow(in::readLine)) != null){ + System.out.println("resp: " + x); + } + + Assertions.assertDoesNotThrow(in::close); Assertions.assertDoesNotThrow(out::close); Assertions.assertDoesNotThrow(clientSocket::close); From eb9e351de6f63fe116278a28aa0215bee7b95f41 Mon Sep 17 00:00:00 2001 From: eemhu <125959687+eemhu@users.noreply.github.com> Date: Mon, 30 Mar 2026 15:22:23 +0300 Subject: [PATCH 16/45] ServerReceivingTest added, along with SendingClock&Factory --- .../net_01/channel/context/SendingClock.java | 34 +++++++++ .../channel/context/SendingClockFactory.java | 16 +++++ .../channel/context/StringWriteable.java | 45 ++++++++++++ ...rverTest.java => ServerReceivingTest.java} | 32 +-------- .../channel/server/ServerSendingTest.java | 70 +++++++++++++++++++ 5 files changed, 166 insertions(+), 31 deletions(-) create mode 100644 src/test/java/com/teragrep/net_01/channel/context/SendingClock.java create mode 100644 src/test/java/com/teragrep/net_01/channel/context/SendingClockFactory.java create mode 100644 src/test/java/com/teragrep/net_01/channel/context/StringWriteable.java rename src/test/java/com/teragrep/net_01/channel/server/{ServerTest.java => ServerReceivingTest.java} (76%) create mode 100644 src/test/java/com/teragrep/net_01/channel/server/ServerSendingTest.java diff --git a/src/test/java/com/teragrep/net_01/channel/context/SendingClock.java b/src/test/java/com/teragrep/net_01/channel/context/SendingClock.java new file mode 100644 index 0000000..a010dba --- /dev/null +++ b/src/test/java/com/teragrep/net_01/channel/context/SendingClock.java @@ -0,0 +1,34 @@ +package com.teragrep.net_01.channel.context; + +import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; + +import java.util.function.Consumer; + +public final class SendingClock implements Clock { + private final EstablishedContext ctx; + private final Consumer consumer; + + public SendingClock(final EstablishedContext ctx, final Consumer consumer) { + this.ctx = ctx; + this.consumer = consumer; + } + + @Override + public void advance(final TrackedMemorySegmentLease bufferLease) { + final StringBuilder stringBuilder = new StringBuilder(); + while (bufferLease.hasNext()) { + stringBuilder.append((char)bufferLease.next().byteValue()); + } + + final String str = stringBuilder.toString(); + + ctx.egress().accept(new StringWriteable(str)); + + consumer.accept(str); + } + + @Override + public void close() throws Exception { + // no-op + } +} diff --git a/src/test/java/com/teragrep/net_01/channel/context/SendingClockFactory.java b/src/test/java/com/teragrep/net_01/channel/context/SendingClockFactory.java new file mode 100644 index 0000000..0ab630e --- /dev/null +++ b/src/test/java/com/teragrep/net_01/channel/context/SendingClockFactory.java @@ -0,0 +1,16 @@ +package com.teragrep.net_01.channel.context; + +import java.util.function.Consumer; + +public final class SendingClockFactory implements ClockFactory { + private final Consumer consumer; + + public SendingClockFactory(final Consumer consumer) { + this.consumer = consumer; + } + + @Override + public Clock create(final EstablishedContext establishedContext) { + return new SendingClock(establishedContext, consumer); + } +} diff --git a/src/test/java/com/teragrep/net_01/channel/context/StringWriteable.java b/src/test/java/com/teragrep/net_01/channel/context/StringWriteable.java new file mode 100644 index 0000000..92cebcf --- /dev/null +++ b/src/test/java/com/teragrep/net_01/channel/context/StringWriteable.java @@ -0,0 +1,45 @@ +package com.teragrep.net_01.channel.context; + +import com.teragrep.net_01.channel.buffer.writable.Writeable; + +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; + +public final class StringWriteable implements Writeable { + private final ByteBuffer[] buffers; + + public StringWriteable(final String str) { + this(new ByteBuffer[]{ByteBuffer.wrap(str.getBytes(StandardCharsets.UTF_8))}); + } + + public StringWriteable(final ByteBuffer[] buffers) { + this.buffers = buffers; + } + + @Override + public void close() { + // no-op + } + + @Override + public ByteBuffer[] buffers() { + return buffers; + } + + @Override + public boolean hasRemaining() { + boolean rv = false; + for (final ByteBuffer buffer : buffers) { + if (buffer.hasRemaining()) { + rv = true; + break; + } + } + return rv; + } + + @Override + public boolean isStub() { + return false; + } +} diff --git a/src/test/java/com/teragrep/net_01/channel/server/ServerTest.java b/src/test/java/com/teragrep/net_01/channel/server/ServerReceivingTest.java similarity index 76% rename from src/test/java/com/teragrep/net_01/channel/server/ServerTest.java rename to src/test/java/com/teragrep/net_01/channel/server/ServerReceivingTest.java index 1f720fb..be305d3 100644 --- a/src/test/java/com/teragrep/net_01/channel/server/ServerTest.java +++ b/src/test/java/com/teragrep/net_01/channel/server/ServerReceivingTest.java @@ -19,7 +19,7 @@ import java.util.concurrent.Executors; @TestInstance(TestInstance.Lifecycle.PER_CLASS) -public final class ServerTest { +public final class ServerReceivingTest { private Server server; private CountDownLatch countDownLatch; private final List> messages = new ArrayList<>(); @@ -94,36 +94,6 @@ void testReceivingThreeChars() { Assertions.assertEquals(List.of((byte) 'a', (byte) 'b', (byte) 'c'), messages.getFirst()); - Assertions.assertDoesNotThrow(in::close); - Assertions.assertDoesNotThrow(out::close); - Assertions.assertDoesNotThrow(clientSocket::close); - } - - @Test - void testSending() { - this.countDownLatch = new CountDownLatch(1); - final java.net.Socket clientSocket = Assertions.assertDoesNotThrow(() -> new java.net.Socket("localhost", 9090)); - - final PrintWriter out = new PrintWriter(Assertions.assertDoesNotThrow(clientSocket::getOutputStream), true); - final BufferedReader in = new BufferedReader(new InputStreamReader(Assertions.assertDoesNotThrow(clientSocket::getInputStream))); - - out.print("a"); - out.flush(); - out.print("b"); - out.flush(); - out.print("c"); - out.flush(); - - Assertions.assertDoesNotThrow(() -> countDownLatch.await()); - - Assertions.assertEquals(List.of((byte) 'a', (byte) 'b', (byte) 'c'), messages.getFirst()); - - String x; - while ((x = Assertions.assertDoesNotThrow(in::readLine)) != null){ - System.out.println("resp: " + x); - } - - Assertions.assertDoesNotThrow(in::close); Assertions.assertDoesNotThrow(out::close); Assertions.assertDoesNotThrow(clientSocket::close); diff --git a/src/test/java/com/teragrep/net_01/channel/server/ServerSendingTest.java b/src/test/java/com/teragrep/net_01/channel/server/ServerSendingTest.java new file mode 100644 index 0000000..2ad96ba --- /dev/null +++ b/src/test/java/com/teragrep/net_01/channel/server/ServerSendingTest.java @@ -0,0 +1,70 @@ +package com.teragrep.net_01.channel.server; + +import com.teragrep.net_01.channel.context.ClockFactory; +import com.teragrep.net_01.channel.context.ConsumingClockFactory; +import com.teragrep.net_01.channel.context.SendingClockFactory; +import com.teragrep.net_01.channel.socket.PlainFactory; +import com.teragrep.net_01.channel.socket.SocketFactory; +import com.teragrep.net_01.eventloop.EventLoop; +import com.teragrep.net_01.eventloop.EventLoopFactory; +import com.teragrep.net_01.server.Server; +import com.teragrep.net_01.server.ServerFactory; +import org.junit.jupiter.api.*; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executors; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public final class ServerSendingTest { + private Server server; + private CountDownLatch countDownLatch; + @BeforeAll + void beforeAll() { + final EventLoopFactory eventLoopFactory = new EventLoopFactory(); + final SocketFactory socketFactory = new PlainFactory(); + final ClockFactory clockFactory = new SendingClockFactory((msgStr) -> countDownLatch.countDown()); + + final EventLoop el = Assertions.assertDoesNotThrow(eventLoopFactory::create); + + // eventLoopThread must run, otherwise nothing will be processed + final Thread elT = new Thread(el); + elT.start(); + + final ServerFactory serverFactory = new ServerFactory(el, + Executors.newSingleThreadExecutor(), socketFactory, clockFactory); + + this.server = Assertions.assertDoesNotThrow(() -> serverFactory.create(9090)); + } + + @AfterAll + void afterAll() { + Assertions.assertDoesNotThrow(this.server::close); + } + + @Test + void testSending() { + this.countDownLatch = new CountDownLatch(1); + final java.net.Socket clientSocket = Assertions.assertDoesNotThrow(() -> new java.net.Socket("localhost", 9090)); + + final PrintWriter out = new PrintWriter(Assertions.assertDoesNotThrow(clientSocket::getOutputStream), true); + final BufferedReader in = new BufferedReader(new InputStreamReader(Assertions.assertDoesNotThrow(clientSocket::getInputStream))); + final String request = "Hello world! This is some input"; + out.println(request); + out.flush(); + + Assertions.assertDoesNotThrow(() -> countDownLatch.await()); + + final String resp = Assertions.assertDoesNotThrow(in::readLine); + + // SendingClock replies with the request + Assertions.assertEquals(request, resp); + Assertions.assertDoesNotThrow(in::close); + Assertions.assertDoesNotThrow(out::close); + Assertions.assertDoesNotThrow(clientSocket::close); + } +} From 65b9d8e12412f505347ec49ccc1dc9fa57eed60c Mon Sep 17 00:00:00 2001 From: eemhu <125959687+eemhu@users.noreply.github.com> Date: Tue, 7 Apr 2026 11:48:54 +0300 Subject: [PATCH 17/45] IOResult stuff / SocketTest fix --- .../buffer/TrackedMemorySegmentLease.java | 9 ++ .../channel/buffer/writable/Writeable.java | 6 +- .../buffer/writable/WriteableAccess.java | 6 +- .../buffer/writable/WriteableClosure.java | 6 +- .../writable/WriteableInvalidation.java | 17 ++- .../buffer/writable/WriteableLeaseful.java | 7 +- .../buffer/writable/WriteableStub.java | 6 +- .../channel/buffer/writable/Writeables.java | 15 +-- .../net_01/channel/context/EgressImpl.java | 15 ++- .../net_01/channel/context/IngressImpl.java | 40 ++----- .../net_01/channel/socket/IOResult.java | 10 ++ .../net_01/channel/socket/PlainSocket.java | 105 +++++++++++++++++- .../net_01/channel/socket/ReadResult.java | 25 +++++ .../net_01/channel/socket/Socket.java | 7 +- .../net_01/channel/socket/TLSSocket.java | 12 +- .../net_01/channel/socket/WrittenResult.java | 25 +++++ .../net_01/channel/LeaseToString.java | 35 ++++++ .../net_01/channel/context/SendingClock.java | 8 +- .../channel/context/SendingClockFactory.java | 8 +- .../channel/context/StringWriteable.java | 26 +++-- .../channel/server/ServerSendingTest.java | 10 +- .../net_01/channel/socket/SocketFake.java | 12 +- .../net_01/channel/socket/SocketTest.java | 93 ++++++++++++---- 23 files changed, 388 insertions(+), 115 deletions(-) create mode 100644 src/main/java/com/teragrep/net_01/channel/socket/IOResult.java create mode 100644 src/main/java/com/teragrep/net_01/channel/socket/ReadResult.java create mode 100644 src/main/java/com/teragrep/net_01/channel/socket/WrittenResult.java create mode 100644 src/test/java/com/teragrep/net_01/channel/LeaseToString.java diff --git a/src/main/java/com/teragrep/net_01/channel/buffer/TrackedMemorySegmentLease.java b/src/main/java/com/teragrep/net_01/channel/buffer/TrackedMemorySegmentLease.java index 6ab14b2..5022d03 100644 --- a/src/main/java/com/teragrep/net_01/channel/buffer/TrackedMemorySegmentLease.java +++ b/src/main/java/com/teragrep/net_01/channel/buffer/TrackedMemorySegmentLease.java @@ -91,4 +91,13 @@ public long position() { public long limit() { return limit.get(); } + + public long limit(int index) { + if (index < 0 || index > leasedObject().byteSize()) { + throw new IndexOutOfBoundsException("Out of bounds"); + } + + limit.set(index); + return limit.get(); + } } diff --git a/src/main/java/com/teragrep/net_01/channel/buffer/writable/Writeable.java b/src/main/java/com/teragrep/net_01/channel/buffer/writable/Writeable.java index 2fefc6f..2298cbf 100644 --- a/src/main/java/com/teragrep/net_01/channel/buffer/writable/Writeable.java +++ b/src/main/java/com/teragrep/net_01/channel/buffer/writable/Writeable.java @@ -45,15 +45,17 @@ */ package com.teragrep.net_01.channel.buffer.writable; +import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; + import java.io.Closeable; -import java.nio.ByteBuffer; +import java.util.List; public interface Writeable extends Closeable { @Override void close(); - ByteBuffer[] buffers(); + List memorySegmentLeases(); boolean hasRemaining(); diff --git a/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableAccess.java b/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableAccess.java index c78778a..8a47e8c 100644 --- a/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableAccess.java +++ b/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableAccess.java @@ -45,10 +45,12 @@ */ package com.teragrep.net_01.channel.buffer.writable; +import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; import com.teragrep.net_01.channel.buffer.access.Access; import com.teragrep.net_01.channel.buffer.access.Lease; import java.nio.ByteBuffer; +import java.util.List; public final class WriteableAccess implements Writeable { @@ -61,10 +63,10 @@ public WriteableAccess(Writeable writeable, Access access) { } @Override - public ByteBuffer[] buffers() { + public List memorySegmentLeases() { // FIXME just not right try (Lease ignored = access.get()) { - return writeable.buffers(); + return writeable.memorySegmentLeases(); } } diff --git a/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableClosure.java b/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableClosure.java index 1e2e88e..1d4e748 100644 --- a/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableClosure.java +++ b/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableClosure.java @@ -45,11 +45,13 @@ */ package com.teragrep.net_01.channel.buffer.writable; +import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; import com.teragrep.net_01.channel.context.EstablishedContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.nio.ByteBuffer; +import java.util.List; /** * Closes a connection at close() @@ -81,8 +83,8 @@ public void close() { } @Override - public ByteBuffer[] buffers() { - return writeable.buffers(); + public List memorySegmentLeases() { + return writeable.memorySegmentLeases(); } @Override diff --git a/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableInvalidation.java b/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableInvalidation.java index fddb2dd..5148931 100644 --- a/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableInvalidation.java +++ b/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableInvalidation.java @@ -45,11 +45,14 @@ */ package com.teragrep.net_01.channel.buffer.writable; +import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; + import java.nio.ByteBuffer; +import java.util.List; /** * Decoration of {@link Writeable} Invalidates a writable so that {@link ByteBuffer}s returned from - * {@link Writeable#buffers()} have position and limit set to zero. Because ByteBuffer can not be Decorated directly + * {@link Writeable#memorySegmentLeases()} have position and limit set to zero. Because ByteBuffer can not be Decorated directly * this is only viable alternative to best-effort invalidate access to it. */ public final class WriteableInvalidation implements Writeable { @@ -62,15 +65,19 @@ public WriteableInvalidation(Writeable writeable) { @Override public void close() { - for (ByteBuffer byteBuffer : buffers()) { - byteBuffer.limit(0); + for (final TrackedMemorySegmentLease lease : memorySegmentLeases()) { + try { + lease.close(); + } catch (final Exception e) { + throw new RuntimeException("Error occurred whilst closing lease", e); + } } writeable.close(); } @Override - public ByteBuffer[] buffers() { - return writeable.buffers(); + public List memorySegmentLeases() { + return writeable.memorySegmentLeases(); } @Override diff --git a/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableLeaseful.java b/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableLeaseful.java index bc8c201..16dc518 100644 --- a/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableLeaseful.java +++ b/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableLeaseful.java @@ -46,11 +46,10 @@ package com.teragrep.net_01.channel.buffer.writable; import com.teragrep.buf_01.buffer.lease.OpenableLease; +import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.IOException; -import java.io.UncheckedIOException; import java.lang.foreign.MemorySegment; import java.nio.ByteBuffer; import java.util.List; @@ -68,8 +67,8 @@ public WriteableLeaseful(Writeable writeable, List> } @Override - public ByteBuffer[] buffers() { - return writeable.buffers(); + public List memorySegmentLeases() { + return writeable.memorySegmentLeases(); } @Override diff --git a/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableStub.java b/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableStub.java index 341afef..ff96133 100644 --- a/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableStub.java +++ b/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableStub.java @@ -45,12 +45,14 @@ */ package com.teragrep.net_01.channel.buffer.writable; -import java.nio.ByteBuffer; +import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; + +import java.util.List; public final class WriteableStub implements Writeable { @Override - public ByteBuffer[] buffers() { + public List memorySegmentLeases() { throw new UnsupportedOperationException("WriteableStub does not allow this method"); } diff --git a/src/main/java/com/teragrep/net_01/channel/buffer/writable/Writeables.java b/src/main/java/com/teragrep/net_01/channel/buffer/writable/Writeables.java index c67c751..3664520 100644 --- a/src/main/java/com/teragrep/net_01/channel/buffer/writable/Writeables.java +++ b/src/main/java/com/teragrep/net_01/channel/buffer/writable/Writeables.java @@ -45,7 +45,11 @@ */ package com.teragrep.net_01.channel.buffer.writable; +import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; + import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; public final class Writeables implements Writeable { @@ -56,10 +60,10 @@ public Writeables(Writeable ... writeables) { } @Override - public ByteBuffer[] buffers() { + public List memorySegmentLeases() { long totalBuffers = 0; for (Writeable writeable : writeables) { - totalBuffers = totalBuffers + writeable.buffers().length; + totalBuffers = totalBuffers + writeable.memorySegmentLeases().size(); } if (totalBuffers > Integer.MAX_VALUE) { @@ -68,12 +72,9 @@ public ByteBuffer[] buffers() { ); } - ByteBuffer[] bufferArray = new ByteBuffer[(int) totalBuffers]; - int written = 0; + List bufferArray = new ArrayList<>((int) totalBuffers); for (final Writeable writeable : writeables) { - int bufferLength = writeable.buffers().length; - System.arraycopy(writeable.buffers(), 0, bufferArray, written, bufferLength); - written += bufferLength; + bufferArray.addAll(writeable.memorySegmentLeases()); } return bufferArray; diff --git a/src/main/java/com/teragrep/net_01/channel/context/EgressImpl.java b/src/main/java/com/teragrep/net_01/channel/context/EgressImpl.java index 536e48f..c53acd4 100644 --- a/src/main/java/com/teragrep/net_01/channel/context/EgressImpl.java +++ b/src/main/java/com/teragrep/net_01/channel/context/EgressImpl.java @@ -45,8 +45,11 @@ */ package com.teragrep.net_01.channel.context; +import com.teragrep.buf_01.buffer.lease.OpenableLease; +import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; import com.teragrep.net_01.channel.buffer.writable.Writeable; import com.teragrep.net_01.channel.buffer.writable.WriteableStub; +import com.teragrep.net_01.channel.socket.WrittenResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import tlschannel.NeedsReadException; @@ -54,13 +57,16 @@ import java.io.IOException; +import java.lang.foreign.MemorySegment; import java.nio.ByteBuffer; import java.nio.channels.CancelledKeyException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; @@ -169,17 +175,17 @@ private void transmit(final List toWriteList) throws IOException { Iterator toWriteIterator = toWriteList.iterator(); while (toWriteIterator.hasNext()) { Writeable w = toWriteIterator.next(); - numberOfBuffers += w.buffers().length; + numberOfBuffers += w.memorySegmentLeases().size(); } - ByteBuffer[] writeBuffers = new ByteBuffer[numberOfBuffers]; + TrackedMemorySegmentLease[] writeBuffers = new TrackedMemorySegmentLease[numberOfBuffers]; int writeBuffersIndex = 0; Iterator toWriteIterator2 = toWriteList.iterator(); while (toWriteIterator2.hasNext()) { Writeable w = toWriteIterator2.next(); - for (ByteBuffer buffer : w.buffers()) { + for (TrackedMemorySegmentLease buffer : w.memorySegmentLeases()) { writeBuffers[writeBuffersIndex] = buffer; writeBuffersIndex++; } @@ -188,7 +194,8 @@ private void transmit(final List toWriteList) throws IOException { writeInProgressList.add(w); } - establishedContext.socket().write(writeBuffers); + + final WrittenResult result = establishedContext.socket().write(writeBuffers); // remove written ones Iterator writeableIterator = writeInProgressList.iterator(); diff --git a/src/main/java/com/teragrep/net_01/channel/context/IngressImpl.java b/src/main/java/com/teragrep/net_01/channel/context/IngressImpl.java index 2786965..f108859 100644 --- a/src/main/java/com/teragrep/net_01/channel/context/IngressImpl.java +++ b/src/main/java/com/teragrep/net_01/channel/context/IngressImpl.java @@ -49,6 +49,7 @@ import com.teragrep.buf_01.buffer.lease.OpenableLease; import com.teragrep.buf_01.buffer.pool.LeaseMultiGet; import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; +import com.teragrep.net_01.channel.socket.ReadResult; import com.teragrep.poj_01.pool.Pool; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -237,49 +238,22 @@ private long readData() throws IOException { List> bufferLeases = new LeaseMultiGet(memorySegmentLeasePool).get(4); - List byteBufferList = new LinkedList<>(); + List trackedMemorySegmentLeases = new LinkedList<>(); for (OpenableLease bufferLease : bufferLeases) { if (bufferLease.isStub()) { continue; } - byteBufferList.add(bufferLease.leasedObject().asByteBuffer()); + trackedMemorySegmentLeases.add(new TrackedMemorySegmentLease(bufferLease)); } - ByteBuffer[] byteBufferArray = byteBufferList.toArray(new ByteBuffer[0]); - readBytes = establishedContext.socket().read(byteBufferArray); - System.out.println("readBytes = " + readBytes); - long bytesLeft = readBytes; - boolean allRead = false; - for (final OpenableLease bufferLease : bufferLeases) { - final long byteSize = bufferLease.leasedObject().byteSize(); - - if (!allRead && readBytes > 0) { - // same as ByteBuffer.flip() - final long diff = bytesLeft - byteSize; - if (diff < 0) { - // mem.segment bigger than bytes left. - // set limit to read amount. - final long limit = byteSize - Math.abs(diff); - activeBuffers.add(new TrackedMemorySegmentLease(bufferLease, new AtomicLong(0L), new AtomicLong(limit))); - } - else { - //else: full mem.segment used, no need to set limit. - activeBuffers.add(new TrackedMemorySegmentLease(bufferLease)); - } - } - - bytesLeft -= byteSize; - - if (bytesLeft <= 0) { - allRead = true; - } - } + final ReadResult result = establishedContext.socket().read(trackedMemorySegmentLeases); + activeBuffers.addAll(result.leases()); System.out.println("buffers.size=" + activeBuffers.size()); - LOGGER.debug("establishedContext.read got <{}> bytes from socket", readBytes); + LOGGER.debug("establishedContext.read got <{}> bytes from socket", result.bytes()); - return readBytes; + return result.bytes(); } public AtomicBoolean needWrite() { diff --git a/src/main/java/com/teragrep/net_01/channel/socket/IOResult.java b/src/main/java/com/teragrep/net_01/channel/socket/IOResult.java new file mode 100644 index 0000000..65326f8 --- /dev/null +++ b/src/main/java/com/teragrep/net_01/channel/socket/IOResult.java @@ -0,0 +1,10 @@ +package com.teragrep.net_01.channel.socket; + +import com.teragrep.buf_01.buffer.lease.Lease; + +import java.util.List; + +public interface IOResult> { + public abstract long bytes(); + public abstract List leases(); +} diff --git a/src/main/java/com/teragrep/net_01/channel/socket/PlainSocket.java b/src/main/java/com/teragrep/net_01/channel/socket/PlainSocket.java index 519ab3f..8d48704 100644 --- a/src/main/java/com/teragrep/net_01/channel/socket/PlainSocket.java +++ b/src/main/java/com/teragrep/net_01/channel/socket/PlainSocket.java @@ -45,9 +45,18 @@ */ package com.teragrep.net_01.channel.socket; +import com.teragrep.buf_01.buffer.lease.OpenableLease; +import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; + import java.io.IOException; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.ValueLayout; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.atomic.AtomicLong; final class PlainSocket implements Socket { @@ -61,13 +70,101 @@ final class PlainSocket implements Socket { } @Override - public long read(ByteBuffer[] dsts) throws IOException { - return socketChannel.read(dsts); + public ReadResult read(List srcs) throws IOException { + final List rv = new ArrayList<>(srcs.size()); + final List byteBuffers = new ArrayList<>(srcs.size()); + srcs.forEach(src -> { + byteBuffers.add(src.leasedObject().asByteBuffer()); + }); + + final long readBytes = socketChannel.read(byteBuffers.toArray(new ByteBuffer[0])); + + long bytesLeft = readBytes; + boolean allRead = false; + for (final TrackedMemorySegmentLease bufferLease : srcs) { + final long byteSize = bufferLease.leasedObject().byteSize(); + + if (!allRead && readBytes > 0) { + // same as ByteBuffer.flip() + final long diff = bytesLeft - byteSize; + if (diff < 0) { + // mem.segment bigger than bytes left. + // set limit to read amount. + final long limit = byteSize - Math.abs(diff); + rv.add(new TrackedMemorySegmentLease(bufferLease, new AtomicLong(0L), new AtomicLong(limit))); + } + else { + //else: full mem.segment used, no need to set limit. + rv.add(new TrackedMemorySegmentLease(bufferLease)); + } + } + + bytesLeft -= byteSize; + + if (bytesLeft <= 0) { + allRead = true; + } + } + + //rv.forEach(l -> { + System.out.println("Lease:"); + /*for (long i = 0 ; i < l.leasedObject().byteSize(); i++) { + System.out.printf("%s", (char)l.leasedObject().get(ValueLayout.JAVA_BYTE, i)); + }*/ + + /* while (l.hasNext()) { + System.out.printf("%s", (char)l.next().byteValue()); + } + + System.out.println();*/ + //}); + return new ReadResult(readBytes, rv); } @Override - public long write(ByteBuffer[] dsts) throws IOException { - return socketChannel.write(dsts); + public WrittenResult write(List leases) throws IOException { + final List buffersToWrite = new ArrayList<>(leases.size()); + final List rv = new ArrayList<>(leases.size()); + + for (final TrackedMemorySegmentLease lease : leases) { + buffersToWrite.add(lease.leasedObject().asByteBuffer()); + } + + final long bytesWritten = socketChannel.write(buffersToWrite.toArray(new ByteBuffer[0])); + System.out.println("wrote bytes: " + bytesWritten); + + long bytesLeft = bytesWritten; + boolean allWritten = false; + for (final TrackedMemorySegmentLease bufferLease : leases) { + final long byteSize = bufferLease.leasedObject().byteSize(); + + if (!allWritten && bytesWritten > 0) { + // same as ByteBuffer.flip() + final long diff = bytesLeft - byteSize; + if (diff < 0) { + // mem.segment bigger than bytes left. + // set limit to written amount. + final long limit = byteSize - Math.abs(diff); + rv.add(new TrackedMemorySegmentLease(bufferLease, new AtomicLong(0L), new AtomicLong(limit))); + } + else { + //else: full mem.segment used, no need to set limit. + rv.add(new TrackedMemorySegmentLease(bufferLease)); + } + } + + bytesLeft -= byteSize; + + if (bytesLeft <= 0) { + allWritten = true; + } + } + + rv.forEach(l -> { + System.out.println(Arrays.toString(l.leasedObject().toArray(ValueLayout.JAVA_BYTE))); + }); + + return new WrittenResult(bytesWritten, rv); } @Override diff --git a/src/main/java/com/teragrep/net_01/channel/socket/ReadResult.java b/src/main/java/com/teragrep/net_01/channel/socket/ReadResult.java new file mode 100644 index 0000000..1907a5b --- /dev/null +++ b/src/main/java/com/teragrep/net_01/channel/socket/ReadResult.java @@ -0,0 +1,25 @@ +package com.teragrep.net_01.channel.socket; + +import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; + +import java.util.List; + +public final class ReadResult implements IOResult { + private final long bytesRead; + private final List leases; + + public ReadResult(final long bytesRead, final List leases) { + this.bytesRead = bytesRead; + this.leases = leases; + } + + @Override + public long bytes() { + return bytesRead; + } + + @Override + public List leases() { + return leases; + } +} diff --git a/src/main/java/com/teragrep/net_01/channel/socket/Socket.java b/src/main/java/com/teragrep/net_01/channel/socket/Socket.java index 67cada1..2b2bd66 100644 --- a/src/main/java/com/teragrep/net_01/channel/socket/Socket.java +++ b/src/main/java/com/teragrep/net_01/channel/socket/Socket.java @@ -45,9 +45,12 @@ */ package com.teragrep.net_01.channel.socket; +import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; + import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; +import java.util.List; /** * {@link Socket} provides network connectivity methods @@ -61,7 +64,7 @@ public interface Socket { * @return amount of bytes read * @throws IOException if read fails */ - long read(ByteBuffer[] dsts) throws IOException; + ReadResult read(List srcs) throws IOException; /** * Write data through a network connection. @@ -70,7 +73,7 @@ public interface Socket { * @return amount of bytes written * @throws IOException if write fails */ - long write(ByteBuffer[] dsts) throws IOException; + WrittenResult write(List dsts) throws IOException; /** * Provides information about a network connection diff --git a/src/main/java/com/teragrep/net_01/channel/socket/TLSSocket.java b/src/main/java/com/teragrep/net_01/channel/socket/TLSSocket.java index dc07b94..c42f9b2 100644 --- a/src/main/java/com/teragrep/net_01/channel/socket/TLSSocket.java +++ b/src/main/java/com/teragrep/net_01/channel/socket/TLSSocket.java @@ -45,11 +45,13 @@ */ package com.teragrep.net_01.channel.socket; +import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; import tlschannel.TlsChannel; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; +import java.util.List; final class TLSSocket implements Socket { @@ -65,13 +67,15 @@ final class TLSSocket implements Socket { } @Override - public long read(ByteBuffer[] dsts) throws IOException { - return tlsChannel.read(dsts); + public ReadResult read(List dsts) throws IOException { + throw new UnsupportedOperationException(); + //return tlsChannel.read(dsts); } @Override - public long write(ByteBuffer[] dsts) throws IOException { - return tlsChannel.write(dsts); + public WrittenResult write(List dsts) throws IOException { + throw new UnsupportedOperationException(); + //return tlsChannel.write(dsts); } @Override diff --git a/src/main/java/com/teragrep/net_01/channel/socket/WrittenResult.java b/src/main/java/com/teragrep/net_01/channel/socket/WrittenResult.java new file mode 100644 index 0000000..0f4946b --- /dev/null +++ b/src/main/java/com/teragrep/net_01/channel/socket/WrittenResult.java @@ -0,0 +1,25 @@ +package com.teragrep.net_01.channel.socket; + +import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; + +import java.util.List; + +public class WrittenResult implements IOResult { + private final long bytesWritten; + private final List leases; + + public WrittenResult(final long bytesWritten, final List leases) { + this.bytesWritten = bytesWritten; + this.leases = leases; + } + + @Override + public long bytes() { + return bytesWritten; + } + + @Override + public List leases() { + return leases; + } +} diff --git a/src/test/java/com/teragrep/net_01/channel/LeaseToString.java b/src/test/java/com/teragrep/net_01/channel/LeaseToString.java new file mode 100644 index 0000000..d5df829 --- /dev/null +++ b/src/test/java/com/teragrep/net_01/channel/LeaseToString.java @@ -0,0 +1,35 @@ +package com.teragrep.net_01.channel; + +import com.teragrep.buf_01.buffer.lease.MemorySegmentLease; +import com.teragrep.buf_01.buffer.lease.OpenableLease; +import com.teragrep.buf_01.buffer.pool.LeaseMultiGet; +import com.teragrep.buf_01.buffer.pool.OpeningPool; +import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; +import com.teragrep.net_01.channel.buffer.writable.Writeable; +import com.teragrep.net_01.channel.context.StringWriteable; + +import java.lang.foreign.MemorySegment; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + +public final class LeaseToString { + + private final String origin; + private final OpeningPool pool; + public LeaseToString(final String origin, OpeningPool pool) { + this.origin = origin; + this.pool = pool; + } + + public Writeable toWriteable() { + byte[] bytes = origin.getBytes(StandardCharsets.UTF_8); + List> leases = new LeaseMultiGet(pool).get(bytes.length); + List trackedLeases = new ArrayList<>(leases.size()); + for (OpenableLease lease : leases) { + trackedLeases.add(new TrackedMemorySegmentLease(lease)); + } + + return new StringWriteable(trackedLeases); + } +} diff --git a/src/test/java/com/teragrep/net_01/channel/context/SendingClock.java b/src/test/java/com/teragrep/net_01/channel/context/SendingClock.java index a010dba..3572f6e 100644 --- a/src/test/java/com/teragrep/net_01/channel/context/SendingClock.java +++ b/src/test/java/com/teragrep/net_01/channel/context/SendingClock.java @@ -1,5 +1,7 @@ package com.teragrep.net_01.channel.context; +import com.teragrep.buf_01.buffer.pool.OpeningPool; +import com.teragrep.net_01.channel.LeaseToString; import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; import java.util.function.Consumer; @@ -7,10 +9,12 @@ public final class SendingClock implements Clock { private final EstablishedContext ctx; private final Consumer consumer; + private final OpeningPool pool; - public SendingClock(final EstablishedContext ctx, final Consumer consumer) { + public SendingClock(final EstablishedContext ctx, final Consumer consumer, final OpeningPool pool) { this.ctx = ctx; this.consumer = consumer; + this.pool = pool; } @Override @@ -22,7 +26,7 @@ public void advance(final TrackedMemorySegmentLease bufferLease) { final String str = stringBuilder.toString(); - ctx.egress().accept(new StringWriteable(str)); + ctx.egress().accept(new LeaseToString(str, pool).toWriteable()); consumer.accept(str); } diff --git a/src/test/java/com/teragrep/net_01/channel/context/SendingClockFactory.java b/src/test/java/com/teragrep/net_01/channel/context/SendingClockFactory.java index 0ab630e..1d9e295 100644 --- a/src/test/java/com/teragrep/net_01/channel/context/SendingClockFactory.java +++ b/src/test/java/com/teragrep/net_01/channel/context/SendingClockFactory.java @@ -1,16 +1,20 @@ package com.teragrep.net_01.channel.context; +import com.teragrep.buf_01.buffer.pool.OpeningPool; + import java.util.function.Consumer; public final class SendingClockFactory implements ClockFactory { private final Consumer consumer; + private final OpeningPool pool; - public SendingClockFactory(final Consumer consumer) { + public SendingClockFactory(final Consumer consumer, final OpeningPool pool) { this.consumer = consumer; + this.pool = pool; } @Override public Clock create(final EstablishedContext establishedContext) { - return new SendingClock(establishedContext, consumer); + return new SendingClock(establishedContext, consumer, pool); } } diff --git a/src/test/java/com/teragrep/net_01/channel/context/StringWriteable.java b/src/test/java/com/teragrep/net_01/channel/context/StringWriteable.java index 92cebcf..588b03c 100644 --- a/src/test/java/com/teragrep/net_01/channel/context/StringWriteable.java +++ b/src/test/java/com/teragrep/net_01/channel/context/StringWriteable.java @@ -1,36 +1,38 @@ package com.teragrep.net_01.channel.context; +import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; import com.teragrep.net_01.channel.buffer.writable.Writeable; -import java.nio.ByteBuffer; -import java.nio.charset.StandardCharsets; +import java.util.List; public final class StringWriteable implements Writeable { - private final ByteBuffer[] buffers; + private final List buffers; - public StringWriteable(final String str) { - this(new ByteBuffer[]{ByteBuffer.wrap(str.getBytes(StandardCharsets.UTF_8))}); - } - - public StringWriteable(final ByteBuffer[] buffers) { + public StringWriteable(final List buffers) { this.buffers = buffers; } @Override public void close() { - // no-op + for (TrackedMemorySegmentLease buf : buffers) { + try { + buf.close(); + } catch (final Exception e) { + throw new RuntimeException(e); + } + } } @Override - public ByteBuffer[] buffers() { + public List memorySegmentLeases() { return buffers; } @Override public boolean hasRemaining() { boolean rv = false; - for (final ByteBuffer buffer : buffers) { - if (buffer.hasRemaining()) { + for (final TrackedMemorySegmentLease buffer : buffers) { + if (buffer.hasNext()) { rv = true; break; } diff --git a/src/test/java/com/teragrep/net_01/channel/server/ServerSendingTest.java b/src/test/java/com/teragrep/net_01/channel/server/ServerSendingTest.java index 2ad96ba..d42676f 100644 --- a/src/test/java/com/teragrep/net_01/channel/server/ServerSendingTest.java +++ b/src/test/java/com/teragrep/net_01/channel/server/ServerSendingTest.java @@ -1,5 +1,8 @@ package com.teragrep.net_01.channel.server; +import com.teragrep.buf_01.buffer.lease.MemorySegmentLeaseStub; +import com.teragrep.buf_01.buffer.pool.OpeningPool; +import com.teragrep.buf_01.buffer.supply.ArenaMemorySegmentLeaseSupplier; import com.teragrep.net_01.channel.context.ClockFactory; import com.teragrep.net_01.channel.context.ConsumingClockFactory; import com.teragrep.net_01.channel.context.SendingClockFactory; @@ -9,11 +12,13 @@ import com.teragrep.net_01.eventloop.EventLoopFactory; import com.teragrep.net_01.server.Server; import com.teragrep.net_01.server.ServerFactory; +import com.teragrep.poj_01.pool.UnboundPool; import org.junit.jupiter.api.*; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.PrintWriter; +import java.lang.foreign.Arena; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CountDownLatch; @@ -23,11 +28,13 @@ public final class ServerSendingTest { private Server server; private CountDownLatch countDownLatch; + private OpeningPool pool; @BeforeAll void beforeAll() { final EventLoopFactory eventLoopFactory = new EventLoopFactory(); final SocketFactory socketFactory = new PlainFactory(); - final ClockFactory clockFactory = new SendingClockFactory((msgStr) -> countDownLatch.countDown()); + this.pool = new OpeningPool(new UnboundPool<>(new ArenaMemorySegmentLeaseSupplier(Arena.ofShared(), 128), new MemorySegmentLeaseStub())); + final ClockFactory clockFactory = new SendingClockFactory((msgStr) -> countDownLatch.countDown(), pool); final EventLoop el = Assertions.assertDoesNotThrow(eventLoopFactory::create); @@ -44,6 +51,7 @@ void beforeAll() { @AfterAll void afterAll() { Assertions.assertDoesNotThrow(this.server::close); + Assertions.assertDoesNotThrow(this.pool::close); } @Test diff --git a/src/test/java/com/teragrep/net_01/channel/socket/SocketFake.java b/src/test/java/com/teragrep/net_01/channel/socket/SocketFake.java index 0263769..b5ba826 100644 --- a/src/test/java/com/teragrep/net_01/channel/socket/SocketFake.java +++ b/src/test/java/com/teragrep/net_01/channel/socket/SocketFake.java @@ -45,8 +45,12 @@ */ package com.teragrep.net_01.channel.socket; +import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; + import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; +import java.util.Collections; +import java.util.List; public class SocketFake implements Socket { @@ -57,13 +61,13 @@ public SocketFake() { } @Override - public long read(ByteBuffer[] dsts) { - return 0; + public ReadResult read(List dsts) { + return new ReadResult(0, Collections.emptyList()); } @Override - public long write(ByteBuffer[] dsts) { - return 0; + public WrittenResult write(List dsts) { + return new WrittenResult(0, Collections.emptyList()); } @Override diff --git a/src/test/java/com/teragrep/net_01/channel/socket/SocketTest.java b/src/test/java/com/teragrep/net_01/channel/socket/SocketTest.java index 5371825..c66b113 100644 --- a/src/test/java/com/teragrep/net_01/channel/socket/SocketTest.java +++ b/src/test/java/com/teragrep/net_01/channel/socket/SocketTest.java @@ -1,19 +1,42 @@ package com.teragrep.net_01.channel.socket; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestInstance; +import com.teragrep.buf_01.buffer.lease.MemorySegmentLeaseStub; +import com.teragrep.buf_01.buffer.lease.OpenableLease; +import com.teragrep.buf_01.buffer.pool.LeaseMultiGet; +import com.teragrep.buf_01.buffer.pool.OpeningPool; +import com.teragrep.buf_01.buffer.supply.ArenaMemorySegmentLeaseSupplier; +import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; +import com.teragrep.poj_01.pool.UnboundPool; +import org.junit.jupiter.api.*; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.PrintWriter; +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.ValueLayout; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.ServerSocketChannel; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; @TestInstance(TestInstance.Lifecycle.PER_CLASS) public final class SocketTest { + private OpeningPool pool; + + @BeforeAll + void beforeAll() { + this.pool = new OpeningPool(new UnboundPool<>(new ArenaMemorySegmentLeaseSupplier(Arena.ofShared(), 128), new MemorySegmentLeaseStub())); + } + + @AfterAll + void afterAll() { + this.pool.close(); + } @Test void testPlainSocketConnection() { @@ -76,10 +99,10 @@ void testPlainSocketRead() { out.println("worldHello"); - ByteBuffer[] bufs = emptyBuffers(1, 10); - socket.read(bufs); + List bufs = emptyBuffers(10); + ReadResult res = socket.read(bufs); - Assertions.assertEquals("worldHello", bufferToString(bufs)); + Assertions.assertEquals("worldHello\n", bufferToString(res.leases())); clientSocket.close(); socketCh.close(); @@ -87,34 +110,58 @@ void testPlainSocketRead() { }); } - private String bufferToString(final ByteBuffer[] bufs) { + private String bufferToString(final List leases) { final StringBuilder stringBuilder = new StringBuilder(); - for (final ByteBuffer buf : bufs) { - buf.flip(); - while (buf.hasRemaining()) { - stringBuilder.append((char) buf.get()); + for (final TrackedMemorySegmentLease buf : leases) { + while (buf.hasNext()) { + stringBuilder.append((char) buf.next().byteValue()); } - buf.flip(); } return stringBuilder.toString(); } - private ByteBuffer[] stringToBuffer(final String str) { - final ByteBuffer[] arr = new ByteBuffer[1]; - + private List stringToBuffer(final String str) { final byte[] bytes = str.getBytes(StandardCharsets.UTF_8); - arr[0] = ByteBuffer.wrap(bytes); + final List leases = emptyBuffers(bytes.length); + + Iterator it = leases.iterator(); + TrackedMemorySegmentLease currentLease = it.next(); + int currentIndex = 0; + long size = currentLease.leasedObject().byteSize(); + for (int i = 0; i < bytes.length; i++) { + System.out.println("i: " + i + " " + bytes[i]); + if (currentIndex < size) { + currentLease.leasedObject().set(ValueLayout.JAVA_BYTE, currentIndex, bytes[i]); + currentIndex++; + } + else { + if (!it.hasNext()) { + throw new IllegalStateException(); + } + currentLease = it.next(); + currentIndex = 0; + size = currentLease.leasedObject().byteSize(); + currentLease.leasedObject().set(ValueLayout.JAVA_BYTE, currentIndex, bytes[i]); + } + } + + + System.out.println("stringToBuffer"); + leases.forEach(l -> { + System.out.println(Arrays.toString(l.leasedObject().toArray(ValueLayout.JAVA_BYTE))); + }); - return arr; + return leases; } - private ByteBuffer[] emptyBuffers(int n, int bytesEach) { - final ByteBuffer[] arr = new ByteBuffer[n]; + private List emptyBuffers(int bytes) { + final List> leases = new LeaseMultiGet(pool).get(bytes); + final List rv = new ArrayList<>(leases.size()); - for (int i = 0; i < n; i++) { - arr[i] = ByteBuffer.allocate(bytesEach); - } + leases.forEach(lease -> { + rv.add(new TrackedMemorySegmentLease(lease)); + }); - return arr; + return rv; } } From 39a719af4e219e88af3bd135cb9a48559797a1ad Mon Sep 17 00:00:00 2001 From: eemhu <125959687+eemhu@users.noreply.github.com> Date: Tue, 7 Apr 2026 13:40:53 +0300 Subject: [PATCH 18/45] fix LeaseToString not writing bytes to lease. fix name to StringToLease --- ...{LeaseToString.java => StringToLease.java} | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) rename src/test/java/com/teragrep/net_01/channel/{LeaseToString.java => StringToLease.java} (55%) diff --git a/src/test/java/com/teragrep/net_01/channel/LeaseToString.java b/src/test/java/com/teragrep/net_01/channel/StringToLease.java similarity index 55% rename from src/test/java/com/teragrep/net_01/channel/LeaseToString.java rename to src/test/java/com/teragrep/net_01/channel/StringToLease.java index d5df829..327d4d3 100644 --- a/src/test/java/com/teragrep/net_01/channel/LeaseToString.java +++ b/src/test/java/com/teragrep/net_01/channel/StringToLease.java @@ -1,6 +1,5 @@ package com.teragrep.net_01.channel; -import com.teragrep.buf_01.buffer.lease.MemorySegmentLease; import com.teragrep.buf_01.buffer.lease.OpenableLease; import com.teragrep.buf_01.buffer.pool.LeaseMultiGet; import com.teragrep.buf_01.buffer.pool.OpeningPool; @@ -13,23 +12,31 @@ import java.util.ArrayList; import java.util.List; -public final class LeaseToString { +public final class StringToLease { private final String origin; private final OpeningPool pool; - public LeaseToString(final String origin, OpeningPool pool) { + public StringToLease(final String origin, OpeningPool pool) { this.origin = origin; this.pool = pool; } public Writeable toWriteable() { - byte[] bytes = origin.getBytes(StandardCharsets.UTF_8); - List> leases = new LeaseMultiGet(pool).get(bytes.length); - List trackedLeases = new ArrayList<>(leases.size()); - for (OpenableLease lease : leases) { + final byte[] bytes = origin.getBytes(StandardCharsets.UTF_8); + final List> leases = new LeaseMultiGet(pool).get(bytes.length); + final List trackedLeases = new ArrayList<>(leases.size()); + for (final OpenableLease lease : leases) { trackedLeases.add(new TrackedMemorySegmentLease(lease)); } + int i = 0; + for (final TrackedMemorySegmentLease trackedLease : trackedLeases) { + while (trackedLease.hasNext() && i < bytes.length) { + trackedLease.write(bytes[i]); + i++; + } + } + return new StringWriteable(trackedLeases); } } From 40b56f8a5672f3b47317118a75e1e67e73cab508 Mon Sep 17 00:00:00 2001 From: eemhu <125959687+eemhu@users.noreply.github.com> Date: Tue, 7 Apr 2026 13:57:56 +0300 Subject: [PATCH 19/45] SendingClock cleanup --- .../teragrep/net_01/channel/context/SendingClock.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/test/java/com/teragrep/net_01/channel/context/SendingClock.java b/src/test/java/com/teragrep/net_01/channel/context/SendingClock.java index 3572f6e..d3ee693 100644 --- a/src/test/java/com/teragrep/net_01/channel/context/SendingClock.java +++ b/src/test/java/com/teragrep/net_01/channel/context/SendingClock.java @@ -1,8 +1,9 @@ package com.teragrep.net_01.channel.context; import com.teragrep.buf_01.buffer.pool.OpeningPool; -import com.teragrep.net_01.channel.LeaseToString; +import com.teragrep.net_01.channel.StringToLease; import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; +import com.teragrep.net_01.channel.buffer.writable.Writeable; import java.util.function.Consumer; @@ -21,12 +22,14 @@ public SendingClock(final EstablishedContext ctx, final Consumer consume public void advance(final TrackedMemorySegmentLease bufferLease) { final StringBuilder stringBuilder = new StringBuilder(); while (bufferLease.hasNext()) { - stringBuilder.append((char)bufferLease.next().byteValue()); + final char c = (char) bufferLease.next().byteValue(); + stringBuilder.append(c); } final String str = stringBuilder.toString(); - ctx.egress().accept(new LeaseToString(str, pool).toWriteable()); + final Writeable w = new StringToLease(str, pool).toWriteable(); + ctx.egress().accept(w); consumer.accept(str); } From 3161d55595e7715247aae8a85b6a4cea7245bba1 Mon Sep 17 00:00:00 2001 From: eemhu <125959687+eemhu@users.noreply.github.com> Date: Wed, 8 Apr 2026 13:37:07 +0300 Subject: [PATCH 20/45] fix `EgressImpl.transmit()` method; PlainSocket now modifies pre-existing TrackedMemorySegmentLeases; add writing and changing position/limit to TrackedMemorySegmentLease; spotless applied --- pom.xml | 2 +- .../buffer/TrackedMemorySegmentLease.java | 70 ++++++++++++++++++- .../buffer/writable/WriteableAccess.java | 1 - .../buffer/writable/WriteableClosure.java | 1 - .../writable/WriteableInvalidation.java | 7 +- .../buffer/writable/WriteableLeaseful.java | 4 +- .../channel/buffer/writable/Writeables.java | 1 - .../net_01/channel/context/Clock.java | 3 - .../net_01/channel/context/EgressImpl.java | 30 ++------ .../context/EstablishedContextImpl.java | 4 +- .../net_01/channel/context/IngressImpl.java | 4 -- .../channel/socket/EncryptionInfoStub.java | 1 - .../channel/socket/EncryptionInfoTLS.java | 1 - .../net_01/channel/socket/IOResult.java | 47 +++++++++++++ .../net_01/channel/socket/PlainSocket.java | 36 +++++----- .../net_01/channel/socket/ReadResult.java | 46 ++++++++++++ .../net_01/channel/socket/TLSSocket.java | 1 - .../net_01/channel/socket/WrittenResult.java | 46 ++++++++++++ .../net_01/channel/StringToLease.java | 46 ++++++++++++ .../channel/context/ConsumingClock.java | 46 ++++++++++++ .../context/ConsumingClockFactory.java | 47 ++++++++++++- .../net_01/channel/context/SendingClock.java | 46 ++++++++++++ .../channel/context/SendingClockFactory.java | 46 ++++++++++++ .../channel/context/StringWriteable.java | 49 ++++++++++++- .../buffer/TrackedMemorySegmentLeaseTest.java | 56 +++++++++++++-- .../channel/server/ServerReceivingTest.java | 68 ++++++++++++++++-- .../channel/server/ServerSendingTest.java | 69 +++++++++++++++--- .../net_01/channel/socket/SocketFake.java | 1 - .../net_01/channel/socket/SocketTest.java | 56 +++++++++++++-- 29 files changed, 743 insertions(+), 92 deletions(-) diff --git a/pom.xml b/pom.xml index 8af5ea9..bcc8ad4 100644 --- a/pom.xml +++ b/pom.xml @@ -37,9 +37,9 @@ UTF-8 UTF-8 0.0.1 + 1.0.0 3.0.0 - diff --git a/src/main/java/com/teragrep/net_01/channel/buffer/TrackedMemorySegmentLease.java b/src/main/java/com/teragrep/net_01/channel/buffer/TrackedMemorySegmentLease.java index 5022d03..15baba8 100644 --- a/src/main/java/com/teragrep/net_01/channel/buffer/TrackedMemorySegmentLease.java +++ b/src/main/java/com/teragrep/net_01/channel/buffer/TrackedMemorySegmentLease.java @@ -1,3 +1,48 @@ +/* + * Java Zero Copy Networking Library net_01 + * Copyright (C) 2024 Suomen Kanuuna Oy + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * + * Additional permission under GNU Affero General Public License version 3 + * section 7 + * + * If you modify this Program, or any covered work, by linking or combining it + * with other code, such other code is not for that reason alone subject to any + * of the requirements of the GNU Affero GPL version 3 as long as this Program + * is the same Program as licensed from Suomen Kanuuna Oy without any additional + * modifications. + * + * Supplemented terms under GNU Affero General Public License version 3 + * section 7 + * + * Origin of the software must be attributed to Suomen Kanuuna Oy. Any modified + * versions must be marked as "Modified version of" The Program. + * + * Names of the licensors and authors may not be used for publicity purposes. + * + * No rights are granted for use of trade names, trademarks, or service marks + * which are in The Program if any. + * + * Licensee must indemnify licensors and authors for any liability that these + * contractual assumptions impose on licensors and authors. + * + * To the extent this program is licensed as part of the Commercial versions of + * Teragrep, the applicable Commercial License may apply to this file if you as + * a licensee so wish it. + */ package com.teragrep.net_01.channel.buffer; import com.teragrep.buf_01.buffer.lease.Lease; @@ -8,6 +53,7 @@ import java.util.concurrent.atomic.AtomicLong; public class TrackedMemorySegmentLease implements Lease, Iterator { + private final Lease origin; private final AtomicLong currentOffset; private final AtomicLong limit; @@ -20,7 +66,11 @@ public TrackedMemorySegmentLease(final Lease origin, final Atomic this(origin, currentOffset, new AtomicLong(-1L)); } - public TrackedMemorySegmentLease(final Lease origin, final AtomicLong currentOffset, final AtomicLong limit) { + public TrackedMemorySegmentLease( + final Lease origin, + final AtomicLong currentOffset, + final AtomicLong limit + ) { this.origin = origin; this.currentOffset = currentOffset; this.limit = limit; @@ -84,14 +134,32 @@ public Byte next() { return origin.leasedObject().get(ValueLayout.JAVA_BYTE, nextIndex); } + public void write(final byte b) { + if (!hasNext()) { + throw new IndexOutOfBoundsException("Reached end of segment or limit, cannot write to next byte"); + } + + final long nextIndex = currentOffset.getAndIncrement(); + + origin.leasedObject().set(ValueLayout.JAVA_BYTE, nextIndex, b); + } + public long position() { return currentOffset.get(); } + public void position(long pos) { + currentOffset.set(pos); + } + public long limit() { return limit.get(); } + public void limit(long newLimit) { + limit.set(newLimit); + } + public long limit(int index) { if (index < 0 || index > leasedObject().byteSize()) { throw new IndexOutOfBoundsException("Out of bounds"); diff --git a/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableAccess.java b/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableAccess.java index 8a47e8c..e0b0fde 100644 --- a/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableAccess.java +++ b/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableAccess.java @@ -49,7 +49,6 @@ import com.teragrep.net_01.channel.buffer.access.Access; import com.teragrep.net_01.channel.buffer.access.Lease; -import java.nio.ByteBuffer; import java.util.List; public final class WriteableAccess implements Writeable { diff --git a/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableClosure.java b/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableClosure.java index 1d4e748..6b3c4d7 100644 --- a/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableClosure.java +++ b/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableClosure.java @@ -50,7 +50,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.nio.ByteBuffer; import java.util.List; /** diff --git a/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableInvalidation.java b/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableInvalidation.java index 5148931..082b674 100644 --- a/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableInvalidation.java +++ b/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableInvalidation.java @@ -52,8 +52,8 @@ /** * Decoration of {@link Writeable} Invalidates a writable so that {@link ByteBuffer}s returned from - * {@link Writeable#memorySegmentLeases()} have position and limit set to zero. Because ByteBuffer can not be Decorated directly - * this is only viable alternative to best-effort invalidate access to it. + * {@link Writeable#memorySegmentLeases()} have position and limit set to zero. Because ByteBuffer can not be Decorated + * directly this is only viable alternative to best-effort invalidate access to it. */ public final class WriteableInvalidation implements Writeable { @@ -68,7 +68,8 @@ public void close() { for (final TrackedMemorySegmentLease lease : memorySegmentLeases()) { try { lease.close(); - } catch (final Exception e) { + } + catch (final Exception e) { throw new RuntimeException("Error occurred whilst closing lease", e); } } diff --git a/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableLeaseful.java b/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableLeaseful.java index 16dc518..36748a2 100644 --- a/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableLeaseful.java +++ b/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableLeaseful.java @@ -51,7 +51,6 @@ import org.slf4j.LoggerFactory; import java.lang.foreign.MemorySegment; -import java.nio.ByteBuffer; import java.util.List; public final class WriteableLeaseful implements Writeable { @@ -92,7 +91,8 @@ public void close() { // FIXME: bufferLease.removeRef(); try { bufferLease.close(); - } catch (Exception e) { + } + catch (Exception e) { throw new RuntimeException(e); } } diff --git a/src/main/java/com/teragrep/net_01/channel/buffer/writable/Writeables.java b/src/main/java/com/teragrep/net_01/channel/buffer/writable/Writeables.java index 3664520..8df719b 100644 --- a/src/main/java/com/teragrep/net_01/channel/buffer/writable/Writeables.java +++ b/src/main/java/com/teragrep/net_01/channel/buffer/writable/Writeables.java @@ -47,7 +47,6 @@ import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; -import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/com/teragrep/net_01/channel/context/Clock.java b/src/main/java/com/teragrep/net_01/channel/context/Clock.java index 710c97a..d1bfca0 100644 --- a/src/main/java/com/teragrep/net_01/channel/context/Clock.java +++ b/src/main/java/com/teragrep/net_01/channel/context/Clock.java @@ -45,11 +45,8 @@ */ package com.teragrep.net_01.channel.context; -import com.teragrep.buf_01.buffer.lease.Lease; import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; -import java.lang.foreign.MemorySegment; - public interface Clock extends AutoCloseable { /** diff --git a/src/main/java/com/teragrep/net_01/channel/context/EgressImpl.java b/src/main/java/com/teragrep/net_01/channel/context/EgressImpl.java index c53acd4..b121545 100644 --- a/src/main/java/com/teragrep/net_01/channel/context/EgressImpl.java +++ b/src/main/java/com/teragrep/net_01/channel/context/EgressImpl.java @@ -45,7 +45,6 @@ */ package com.teragrep.net_01.channel.context; -import com.teragrep.buf_01.buffer.lease.OpenableLease; import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; import com.teragrep.net_01.channel.buffer.writable.Writeable; import com.teragrep.net_01.channel.buffer.writable.WriteableStub; @@ -57,16 +56,12 @@ import java.io.IOException; -import java.lang.foreign.MemorySegment; -import java.nio.ByteBuffer; import java.nio.channels.CancelledKeyException; import java.util.ArrayList; -import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; @@ -170,33 +165,18 @@ public void accept(Writeable writeable) { private void transmit(final List toWriteList) throws IOException { try { + final List writeBuffers = new ArrayList<>(); - int numberOfBuffers = 0; - Iterator toWriteIterator = toWriteList.iterator(); - while (toWriteIterator.hasNext()) { - Writeable w = toWriteIterator.next(); - numberOfBuffers += w.memorySegmentLeases().size(); - } - - TrackedMemorySegmentLease[] writeBuffers = new TrackedMemorySegmentLease[numberOfBuffers]; - int writeBuffersIndex = 0; - - Iterator toWriteIterator2 = toWriteList.iterator(); - while (toWriteIterator2.hasNext()) { - Writeable w = toWriteIterator2.next(); - - for (TrackedMemorySegmentLease buffer : w.memorySegmentLeases()) { - writeBuffers[writeBuffersIndex] = buffer; - writeBuffersIndex++; - } - - toWriteIterator2.remove(); + for (final Writeable w : toWriteList) { + writeBuffers.addAll(w.memorySegmentLeases()); writeInProgressList.add(w); } + LOGGER.info("Writing to socket"); final WrittenResult result = establishedContext.socket().write(writeBuffers); + LOGGER.info("Transmit <{}> byte(s) to socket", result.bytes()); // remove written ones Iterator writeableIterator = writeInProgressList.iterator(); while (writeableIterator.hasNext()) { diff --git a/src/main/java/com/teragrep/net_01/channel/context/EstablishedContextImpl.java b/src/main/java/com/teragrep/net_01/channel/context/EstablishedContextImpl.java index fc18e1c..a26c0e0 100644 --- a/src/main/java/com/teragrep/net_01/channel/context/EstablishedContextImpl.java +++ b/src/main/java/com/teragrep/net_01/channel/context/EstablishedContextImpl.java @@ -84,7 +84,9 @@ final class EstablishedContextImpl implements EstablishedContext { this.executorService = executorService; this.socket = socket; - this.memorySegmentLeasePool = new OpeningPool(new UnboundPool<>(new ArenaMemorySegmentLeaseSupplier(Arena.ofShared(), 4096), new MemorySegmentLeaseStub())); + this.memorySegmentLeasePool = new OpeningPool( + new UnboundPool<>(new ArenaMemorySegmentLeaseSupplier(Arena.ofShared(), 4096), new MemorySegmentLeaseStub()) + ); this.ingress = new IngressImpl(this, this.memorySegmentLeasePool); this.egress = new EgressImpl(this); diff --git a/src/main/java/com/teragrep/net_01/channel/context/IngressImpl.java b/src/main/java/com/teragrep/net_01/channel/context/IngressImpl.java index f108859..de13a10 100644 --- a/src/main/java/com/teragrep/net_01/channel/context/IngressImpl.java +++ b/src/main/java/com/teragrep/net_01/channel/context/IngressImpl.java @@ -45,7 +45,6 @@ */ package com.teragrep.net_01.channel.context; -import com.teragrep.buf_01.buffer.lease.MemorySegmentLease; import com.teragrep.buf_01.buffer.lease.OpenableLease; import com.teragrep.buf_01.buffer.pool.LeaseMultiGet; import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; @@ -58,14 +57,11 @@ import java.io.IOException; import java.lang.foreign.MemorySegment; -import java.nio.ByteBuffer; import java.nio.channels.CancelledKeyException; import java.util.Collections; import java.util.LinkedList; import java.util.List; -import java.util.concurrent.ConcurrentLinkedDeque; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; diff --git a/src/main/java/com/teragrep/net_01/channel/socket/EncryptionInfoStub.java b/src/main/java/com/teragrep/net_01/channel/socket/EncryptionInfoStub.java index 9e059d4..208994a 100644 --- a/src/main/java/com/teragrep/net_01/channel/socket/EncryptionInfoStub.java +++ b/src/main/java/com/teragrep/net_01/channel/socket/EncryptionInfoStub.java @@ -46,7 +46,6 @@ package com.teragrep.net_01.channel.socket; import javax.net.ssl.SSLPeerUnverifiedException; -import javax.security.cert.X509Certificate; import java.security.Principal; import java.security.cert.Certificate; diff --git a/src/main/java/com/teragrep/net_01/channel/socket/EncryptionInfoTLS.java b/src/main/java/com/teragrep/net_01/channel/socket/EncryptionInfoTLS.java index 1517e07..bb08bd2 100644 --- a/src/main/java/com/teragrep/net_01/channel/socket/EncryptionInfoTLS.java +++ b/src/main/java/com/teragrep/net_01/channel/socket/EncryptionInfoTLS.java @@ -48,7 +48,6 @@ import tlschannel.TlsChannel; import javax.net.ssl.SSLPeerUnverifiedException; -import javax.security.cert.X509Certificate; import java.security.Principal; import java.security.cert.Certificate; diff --git a/src/main/java/com/teragrep/net_01/channel/socket/IOResult.java b/src/main/java/com/teragrep/net_01/channel/socket/IOResult.java index 65326f8..247247d 100644 --- a/src/main/java/com/teragrep/net_01/channel/socket/IOResult.java +++ b/src/main/java/com/teragrep/net_01/channel/socket/IOResult.java @@ -1,3 +1,48 @@ +/* + * Java Zero Copy Networking Library net_01 + * Copyright (C) 2024 Suomen Kanuuna Oy + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * + * Additional permission under GNU Affero General Public License version 3 + * section 7 + * + * If you modify this Program, or any covered work, by linking or combining it + * with other code, such other code is not for that reason alone subject to any + * of the requirements of the GNU Affero GPL version 3 as long as this Program + * is the same Program as licensed from Suomen Kanuuna Oy without any additional + * modifications. + * + * Supplemented terms under GNU Affero General Public License version 3 + * section 7 + * + * Origin of the software must be attributed to Suomen Kanuuna Oy. Any modified + * versions must be marked as "Modified version of" The Program. + * + * Names of the licensors and authors may not be used for publicity purposes. + * + * No rights are granted for use of trade names, trademarks, or service marks + * which are in The Program if any. + * + * Licensee must indemnify licensors and authors for any liability that these + * contractual assumptions impose on licensors and authors. + * + * To the extent this program is licensed as part of the Commercial versions of + * Teragrep, the applicable Commercial License may apply to this file if you as + * a licensee so wish it. + */ package com.teragrep.net_01.channel.socket; import com.teragrep.buf_01.buffer.lease.Lease; @@ -5,6 +50,8 @@ import java.util.List; public interface IOResult> { + public abstract long bytes(); + public abstract List leases(); } diff --git a/src/main/java/com/teragrep/net_01/channel/socket/PlainSocket.java b/src/main/java/com/teragrep/net_01/channel/socket/PlainSocket.java index 8d48704..5c6a364 100644 --- a/src/main/java/com/teragrep/net_01/channel/socket/PlainSocket.java +++ b/src/main/java/com/teragrep/net_01/channel/socket/PlainSocket.java @@ -45,16 +45,12 @@ */ package com.teragrep.net_01.channel.socket; -import com.teragrep.buf_01.buffer.lease.OpenableLease; import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; import java.io.IOException; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.ValueLayout; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.concurrent.atomic.AtomicLong; @@ -107,16 +103,16 @@ public ReadResult read(List srcs) throws IOException } //rv.forEach(l -> { - System.out.println("Lease:"); - /*for (long i = 0 ; i < l.leasedObject().byteSize(); i++) { - System.out.printf("%s", (char)l.leasedObject().get(ValueLayout.JAVA_BYTE, i)); - }*/ - - /* while (l.hasNext()) { - System.out.printf("%s", (char)l.next().byteValue()); - } - - System.out.println();*/ + System.out.println("Lease:"); + /*for (long i = 0 ; i < l.leasedObject().byteSize(); i++) { + System.out.printf("%s", (char)l.leasedObject().get(ValueLayout.JAVA_BYTE, i)); + }*/ + + /* while (l.hasNext()) { + System.out.printf("%s", (char)l.next().byteValue()); + } + + System.out.println();*/ //}); return new ReadResult(readBytes, rv); } @@ -145,11 +141,15 @@ public WrittenResult write(List leases) throws IOExce // mem.segment bigger than bytes left. // set limit to written amount. final long limit = byteSize - Math.abs(diff); - rv.add(new TrackedMemorySegmentLease(bufferLease, new AtomicLong(0L), new AtomicLong(limit))); + //rv.add(new TrackedMemorySegmentLease(bufferLease, new AtomicLong(0L), new AtomicLong(limit))); + bufferLease.position(0L); + bufferLease.limit(limit); + rv.add(bufferLease); } else { //else: full mem.segment used, no need to set limit. - rv.add(new TrackedMemorySegmentLease(bufferLease)); + //rv.add(new TrackedMemorySegmentLease(bufferLease)); + rv.add(bufferLease); } } @@ -160,10 +160,6 @@ public WrittenResult write(List leases) throws IOExce } } - rv.forEach(l -> { - System.out.println(Arrays.toString(l.leasedObject().toArray(ValueLayout.JAVA_BYTE))); - }); - return new WrittenResult(bytesWritten, rv); } diff --git a/src/main/java/com/teragrep/net_01/channel/socket/ReadResult.java b/src/main/java/com/teragrep/net_01/channel/socket/ReadResult.java index 1907a5b..fc54de4 100644 --- a/src/main/java/com/teragrep/net_01/channel/socket/ReadResult.java +++ b/src/main/java/com/teragrep/net_01/channel/socket/ReadResult.java @@ -1,3 +1,48 @@ +/* + * Java Zero Copy Networking Library net_01 + * Copyright (C) 2024 Suomen Kanuuna Oy + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * + * Additional permission under GNU Affero General Public License version 3 + * section 7 + * + * If you modify this Program, or any covered work, by linking or combining it + * with other code, such other code is not for that reason alone subject to any + * of the requirements of the GNU Affero GPL version 3 as long as this Program + * is the same Program as licensed from Suomen Kanuuna Oy without any additional + * modifications. + * + * Supplemented terms under GNU Affero General Public License version 3 + * section 7 + * + * Origin of the software must be attributed to Suomen Kanuuna Oy. Any modified + * versions must be marked as "Modified version of" The Program. + * + * Names of the licensors and authors may not be used for publicity purposes. + * + * No rights are granted for use of trade names, trademarks, or service marks + * which are in The Program if any. + * + * Licensee must indemnify licensors and authors for any liability that these + * contractual assumptions impose on licensors and authors. + * + * To the extent this program is licensed as part of the Commercial versions of + * Teragrep, the applicable Commercial License may apply to this file if you as + * a licensee so wish it. + */ package com.teragrep.net_01.channel.socket; import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; @@ -5,6 +50,7 @@ import java.util.List; public final class ReadResult implements IOResult { + private final long bytesRead; private final List leases; diff --git a/src/main/java/com/teragrep/net_01/channel/socket/TLSSocket.java b/src/main/java/com/teragrep/net_01/channel/socket/TLSSocket.java index c42f9b2..f5e0274 100644 --- a/src/main/java/com/teragrep/net_01/channel/socket/TLSSocket.java +++ b/src/main/java/com/teragrep/net_01/channel/socket/TLSSocket.java @@ -49,7 +49,6 @@ import tlschannel.TlsChannel; import java.io.IOException; -import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; import java.util.List; diff --git a/src/main/java/com/teragrep/net_01/channel/socket/WrittenResult.java b/src/main/java/com/teragrep/net_01/channel/socket/WrittenResult.java index 0f4946b..585bad0 100644 --- a/src/main/java/com/teragrep/net_01/channel/socket/WrittenResult.java +++ b/src/main/java/com/teragrep/net_01/channel/socket/WrittenResult.java @@ -1,3 +1,48 @@ +/* + * Java Zero Copy Networking Library net_01 + * Copyright (C) 2024 Suomen Kanuuna Oy + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * + * Additional permission under GNU Affero General Public License version 3 + * section 7 + * + * If you modify this Program, or any covered work, by linking or combining it + * with other code, such other code is not for that reason alone subject to any + * of the requirements of the GNU Affero GPL version 3 as long as this Program + * is the same Program as licensed from Suomen Kanuuna Oy without any additional + * modifications. + * + * Supplemented terms under GNU Affero General Public License version 3 + * section 7 + * + * Origin of the software must be attributed to Suomen Kanuuna Oy. Any modified + * versions must be marked as "Modified version of" The Program. + * + * Names of the licensors and authors may not be used for publicity purposes. + * + * No rights are granted for use of trade names, trademarks, or service marks + * which are in The Program if any. + * + * Licensee must indemnify licensors and authors for any liability that these + * contractual assumptions impose on licensors and authors. + * + * To the extent this program is licensed as part of the Commercial versions of + * Teragrep, the applicable Commercial License may apply to this file if you as + * a licensee so wish it. + */ package com.teragrep.net_01.channel.socket; import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; @@ -5,6 +50,7 @@ import java.util.List; public class WrittenResult implements IOResult { + private final long bytesWritten; private final List leases; diff --git a/src/test/java/com/teragrep/net_01/channel/StringToLease.java b/src/test/java/com/teragrep/net_01/channel/StringToLease.java index 327d4d3..b36003f 100644 --- a/src/test/java/com/teragrep/net_01/channel/StringToLease.java +++ b/src/test/java/com/teragrep/net_01/channel/StringToLease.java @@ -1,3 +1,48 @@ +/* + * Java Zero Copy Networking Library net_01 + * Copyright (C) 2024 Suomen Kanuuna Oy + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * + * Additional permission under GNU Affero General Public License version 3 + * section 7 + * + * If you modify this Program, or any covered work, by linking or combining it + * with other code, such other code is not for that reason alone subject to any + * of the requirements of the GNU Affero GPL version 3 as long as this Program + * is the same Program as licensed from Suomen Kanuuna Oy without any additional + * modifications. + * + * Supplemented terms under GNU Affero General Public License version 3 + * section 7 + * + * Origin of the software must be attributed to Suomen Kanuuna Oy. Any modified + * versions must be marked as "Modified version of" The Program. + * + * Names of the licensors and authors may not be used for publicity purposes. + * + * No rights are granted for use of trade names, trademarks, or service marks + * which are in The Program if any. + * + * Licensee must indemnify licensors and authors for any liability that these + * contractual assumptions impose on licensors and authors. + * + * To the extent this program is licensed as part of the Commercial versions of + * Teragrep, the applicable Commercial License may apply to this file if you as + * a licensee so wish it. + */ package com.teragrep.net_01.channel; import com.teragrep.buf_01.buffer.lease.OpenableLease; @@ -16,6 +61,7 @@ public final class StringToLease { private final String origin; private final OpeningPool pool; + public StringToLease(final String origin, OpeningPool pool) { this.origin = origin; this.pool = pool; diff --git a/src/test/java/com/teragrep/net_01/channel/context/ConsumingClock.java b/src/test/java/com/teragrep/net_01/channel/context/ConsumingClock.java index 1bec299..e89300d 100644 --- a/src/test/java/com/teragrep/net_01/channel/context/ConsumingClock.java +++ b/src/test/java/com/teragrep/net_01/channel/context/ConsumingClock.java @@ -1,3 +1,48 @@ +/* + * Java Zero Copy Networking Library net_01 + * Copyright (C) 2024 Suomen Kanuuna Oy + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * + * Additional permission under GNU Affero General Public License version 3 + * section 7 + * + * If you modify this Program, or any covered work, by linking or combining it + * with other code, such other code is not for that reason alone subject to any + * of the requirements of the GNU Affero GPL version 3 as long as this Program + * is the same Program as licensed from Suomen Kanuuna Oy without any additional + * modifications. + * + * Supplemented terms under GNU Affero General Public License version 3 + * section 7 + * + * Origin of the software must be attributed to Suomen Kanuuna Oy. Any modified + * versions must be marked as "Modified version of" The Program. + * + * Names of the licensors and authors may not be used for publicity purposes. + * + * No rights are granted for use of trade names, trademarks, or service marks + * which are in The Program if any. + * + * Licensee must indemnify licensors and authors for any liability that these + * contractual assumptions impose on licensors and authors. + * + * To the extent this program is licensed as part of the Commercial versions of + * Teragrep, the applicable Commercial License may apply to this file if you as + * a licensee so wish it. + */ package com.teragrep.net_01.channel.context; import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; @@ -7,6 +52,7 @@ import java.util.function.Consumer; public final class ConsumingClock implements Clock { + private final EstablishedContext ctx; private final Consumer> messageConsumer; diff --git a/src/test/java/com/teragrep/net_01/channel/context/ConsumingClockFactory.java b/src/test/java/com/teragrep/net_01/channel/context/ConsumingClockFactory.java index 0f6ae32..359c022 100644 --- a/src/test/java/com/teragrep/net_01/channel/context/ConsumingClockFactory.java +++ b/src/test/java/com/teragrep/net_01/channel/context/ConsumingClockFactory.java @@ -1,3 +1,48 @@ +/* + * Java Zero Copy Networking Library net_01 + * Copyright (C) 2024 Suomen Kanuuna Oy + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * + * Additional permission under GNU Affero General Public License version 3 + * section 7 + * + * If you modify this Program, or any covered work, by linking or combining it + * with other code, such other code is not for that reason alone subject to any + * of the requirements of the GNU Affero GPL version 3 as long as this Program + * is the same Program as licensed from Suomen Kanuuna Oy without any additional + * modifications. + * + * Supplemented terms under GNU Affero General Public License version 3 + * section 7 + * + * Origin of the software must be attributed to Suomen Kanuuna Oy. Any modified + * versions must be marked as "Modified version of" The Program. + * + * Names of the licensors and authors may not be used for publicity purposes. + * + * No rights are granted for use of trade names, trademarks, or service marks + * which are in The Program if any. + * + * Licensee must indemnify licensors and authors for any liability that these + * contractual assumptions impose on licensors and authors. + * + * To the extent this program is licensed as part of the Commercial versions of + * Teragrep, the applicable Commercial License may apply to this file if you as + * a licensee so wish it. + */ package com.teragrep.net_01.channel.context; import java.util.List; @@ -7,7 +52,7 @@ public final class ConsumingClockFactory implements ClockFactory { private final Consumer> messageConsumer; - public ConsumingClockFactory(Consumer> messageConsumer){ + public ConsumingClockFactory(Consumer> messageConsumer) { this.messageConsumer = messageConsumer; } diff --git a/src/test/java/com/teragrep/net_01/channel/context/SendingClock.java b/src/test/java/com/teragrep/net_01/channel/context/SendingClock.java index d3ee693..8e7bf35 100644 --- a/src/test/java/com/teragrep/net_01/channel/context/SendingClock.java +++ b/src/test/java/com/teragrep/net_01/channel/context/SendingClock.java @@ -1,3 +1,48 @@ +/* + * Java Zero Copy Networking Library net_01 + * Copyright (C) 2024 Suomen Kanuuna Oy + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * + * Additional permission under GNU Affero General Public License version 3 + * section 7 + * + * If you modify this Program, or any covered work, by linking or combining it + * with other code, such other code is not for that reason alone subject to any + * of the requirements of the GNU Affero GPL version 3 as long as this Program + * is the same Program as licensed from Suomen Kanuuna Oy without any additional + * modifications. + * + * Supplemented terms under GNU Affero General Public License version 3 + * section 7 + * + * Origin of the software must be attributed to Suomen Kanuuna Oy. Any modified + * versions must be marked as "Modified version of" The Program. + * + * Names of the licensors and authors may not be used for publicity purposes. + * + * No rights are granted for use of trade names, trademarks, or service marks + * which are in The Program if any. + * + * Licensee must indemnify licensors and authors for any liability that these + * contractual assumptions impose on licensors and authors. + * + * To the extent this program is licensed as part of the Commercial versions of + * Teragrep, the applicable Commercial License may apply to this file if you as + * a licensee so wish it. + */ package com.teragrep.net_01.channel.context; import com.teragrep.buf_01.buffer.pool.OpeningPool; @@ -8,6 +53,7 @@ import java.util.function.Consumer; public final class SendingClock implements Clock { + private final EstablishedContext ctx; private final Consumer consumer; private final OpeningPool pool; diff --git a/src/test/java/com/teragrep/net_01/channel/context/SendingClockFactory.java b/src/test/java/com/teragrep/net_01/channel/context/SendingClockFactory.java index 1d9e295..e39c26e 100644 --- a/src/test/java/com/teragrep/net_01/channel/context/SendingClockFactory.java +++ b/src/test/java/com/teragrep/net_01/channel/context/SendingClockFactory.java @@ -1,3 +1,48 @@ +/* + * Java Zero Copy Networking Library net_01 + * Copyright (C) 2024 Suomen Kanuuna Oy + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * + * Additional permission under GNU Affero General Public License version 3 + * section 7 + * + * If you modify this Program, or any covered work, by linking or combining it + * with other code, such other code is not for that reason alone subject to any + * of the requirements of the GNU Affero GPL version 3 as long as this Program + * is the same Program as licensed from Suomen Kanuuna Oy without any additional + * modifications. + * + * Supplemented terms under GNU Affero General Public License version 3 + * section 7 + * + * Origin of the software must be attributed to Suomen Kanuuna Oy. Any modified + * versions must be marked as "Modified version of" The Program. + * + * Names of the licensors and authors may not be used for publicity purposes. + * + * No rights are granted for use of trade names, trademarks, or service marks + * which are in The Program if any. + * + * Licensee must indemnify licensors and authors for any liability that these + * contractual assumptions impose on licensors and authors. + * + * To the extent this program is licensed as part of the Commercial versions of + * Teragrep, the applicable Commercial License may apply to this file if you as + * a licensee so wish it. + */ package com.teragrep.net_01.channel.context; import com.teragrep.buf_01.buffer.pool.OpeningPool; @@ -5,6 +50,7 @@ import java.util.function.Consumer; public final class SendingClockFactory implements ClockFactory { + private final Consumer consumer; private final OpeningPool pool; diff --git a/src/test/java/com/teragrep/net_01/channel/context/StringWriteable.java b/src/test/java/com/teragrep/net_01/channel/context/StringWriteable.java index 588b03c..4474de8 100644 --- a/src/test/java/com/teragrep/net_01/channel/context/StringWriteable.java +++ b/src/test/java/com/teragrep/net_01/channel/context/StringWriteable.java @@ -1,3 +1,48 @@ +/* + * Java Zero Copy Networking Library net_01 + * Copyright (C) 2024 Suomen Kanuuna Oy + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * + * Additional permission under GNU Affero General Public License version 3 + * section 7 + * + * If you modify this Program, or any covered work, by linking or combining it + * with other code, such other code is not for that reason alone subject to any + * of the requirements of the GNU Affero GPL version 3 as long as this Program + * is the same Program as licensed from Suomen Kanuuna Oy without any additional + * modifications. + * + * Supplemented terms under GNU Affero General Public License version 3 + * section 7 + * + * Origin of the software must be attributed to Suomen Kanuuna Oy. Any modified + * versions must be marked as "Modified version of" The Program. + * + * Names of the licensors and authors may not be used for publicity purposes. + * + * No rights are granted for use of trade names, trademarks, or service marks + * which are in The Program if any. + * + * Licensee must indemnify licensors and authors for any liability that these + * contractual assumptions impose on licensors and authors. + * + * To the extent this program is licensed as part of the Commercial versions of + * Teragrep, the applicable Commercial License may apply to this file if you as + * a licensee so wish it. + */ package com.teragrep.net_01.channel.context; import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; @@ -6,6 +51,7 @@ import java.util.List; public final class StringWriteable implements Writeable { + private final List buffers; public StringWriteable(final List buffers) { @@ -17,7 +63,8 @@ public void close() { for (TrackedMemorySegmentLease buf : buffers) { try { buf.close(); - } catch (final Exception e) { + } + catch (final Exception e) { throw new RuntimeException(e); } } diff --git a/src/test/java/com/teragrep/net_01/channel/context/buffer/TrackedMemorySegmentLeaseTest.java b/src/test/java/com/teragrep/net_01/channel/context/buffer/TrackedMemorySegmentLeaseTest.java index 5aa6c73..099ee4f 100644 --- a/src/test/java/com/teragrep/net_01/channel/context/buffer/TrackedMemorySegmentLeaseTest.java +++ b/src/test/java/com/teragrep/net_01/channel/context/buffer/TrackedMemorySegmentLeaseTest.java @@ -1,3 +1,48 @@ +/* + * Java Zero Copy Networking Library net_01 + * Copyright (C) 2024 Suomen Kanuuna Oy + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * + * Additional permission under GNU Affero General Public License version 3 + * section 7 + * + * If you modify this Program, or any covered work, by linking or combining it + * with other code, such other code is not for that reason alone subject to any + * of the requirements of the GNU Affero GPL version 3 as long as this Program + * is the same Program as licensed from Suomen Kanuuna Oy without any additional + * modifications. + * + * Supplemented terms under GNU Affero General Public License version 3 + * section 7 + * + * Origin of the software must be attributed to Suomen Kanuuna Oy. Any modified + * versions must be marked as "Modified version of" The Program. + * + * Names of the licensors and authors may not be used for publicity purposes. + * + * No rights are granted for use of trade names, trademarks, or service marks + * which are in The Program if any. + * + * Licensee must indemnify licensors and authors for any liability that these + * contractual assumptions impose on licensors and authors. + * + * To the extent this program is licensed as part of the Commercial versions of + * Teragrep, the applicable Commercial License may apply to this file if you as + * a licensee so wish it. + */ package com.teragrep.net_01.channel.context.buffer; import com.teragrep.buf_01.buffer.lease.MemorySegmentLeaseStub; @@ -10,11 +55,13 @@ import java.lang.foreign.Arena; -public final class TrackedMemorySegmentLeaseTest -{ +public final class TrackedMemorySegmentLeaseTest { + @Test void testProgressing() { - final OpeningPool pool = new OpeningPool(new UnboundPool<>(new ArenaMemorySegmentLeaseSupplier(Arena.ofShared(), 5), new MemorySegmentLeaseStub())); + final OpeningPool pool = new OpeningPool( + new UnboundPool<>(new ArenaMemorySegmentLeaseSupplier(Arena.ofShared(), 5), new MemorySegmentLeaseStub()) + ); final TrackedMemorySegmentLease trackedLease = new TrackedMemorySegmentLease(pool.get()); Assertions.assertEquals(0L, trackedLease.position()); @@ -23,7 +70,7 @@ void testProgressing() { for (int i = 0; i < 5; i++) { Assertions.assertEquals(i, trackedLease.position()); Assertions.assertTrue(trackedLease.hasNext()); - Assertions.assertEquals((byte)0, trackedLease.next()); + Assertions.assertEquals((byte) 0, trackedLease.next()); loops++; } Assertions.assertEquals(5, loops); @@ -33,4 +80,3 @@ void testProgressing() { Assertions.assertEquals(5L, trackedLease.position()); } } - diff --git a/src/test/java/com/teragrep/net_01/channel/server/ServerReceivingTest.java b/src/test/java/com/teragrep/net_01/channel/server/ServerReceivingTest.java index be305d3..4c2aa3a 100644 --- a/src/test/java/com/teragrep/net_01/channel/server/ServerReceivingTest.java +++ b/src/test/java/com/teragrep/net_01/channel/server/ServerReceivingTest.java @@ -1,3 +1,48 @@ +/* + * Java Zero Copy Networking Library net_01 + * Copyright (C) 2024 Suomen Kanuuna Oy + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * + * Additional permission under GNU Affero General Public License version 3 + * section 7 + * + * If you modify this Program, or any covered work, by linking or combining it + * with other code, such other code is not for that reason alone subject to any + * of the requirements of the GNU Affero GPL version 3 as long as this Program + * is the same Program as licensed from Suomen Kanuuna Oy without any additional + * modifications. + * + * Supplemented terms under GNU Affero General Public License version 3 + * section 7 + * + * Origin of the software must be attributed to Suomen Kanuuna Oy. Any modified + * versions must be marked as "Modified version of" The Program. + * + * Names of the licensors and authors may not be used for publicity purposes. + * + * No rights are granted for use of trade names, trademarks, or service marks + * which are in The Program if any. + * + * Licensee must indemnify licensors and authors for any liability that these + * contractual assumptions impose on licensors and authors. + * + * To the extent this program is licensed as part of the Commercial versions of + * Teragrep, the applicable Commercial License may apply to this file if you as + * a licensee so wish it. + */ package com.teragrep.net_01.channel.server; import com.teragrep.net_01.channel.context.ClockFactory; @@ -20,6 +65,7 @@ @TestInstance(TestInstance.Lifecycle.PER_CLASS) public final class ServerReceivingTest { + private Server server; private CountDownLatch countDownLatch; private final List> messages = new ArrayList<>(); @@ -39,8 +85,12 @@ void beforeAll() { final Thread elT = new Thread(el); elT.start(); - final ServerFactory serverFactory = new ServerFactory(el, - Executors.newSingleThreadExecutor(), socketFactory, clockFactory); + final ServerFactory serverFactory = new ServerFactory( + el, + Executors.newSingleThreadExecutor(), + socketFactory, + clockFactory + ); this.server = Assertions.assertDoesNotThrow(() -> serverFactory.create(9090)); } @@ -58,10 +108,13 @@ void afterEach() { @Test void testReceivingOneChar() { this.countDownLatch = new CountDownLatch(1); - final java.net.Socket clientSocket = Assertions.assertDoesNotThrow(() -> new java.net.Socket("localhost", 9090)); + final java.net.Socket clientSocket = Assertions + .assertDoesNotThrow(() -> new java.net.Socket("localhost", 9090)); final PrintWriter out = new PrintWriter(Assertions.assertDoesNotThrow(clientSocket::getOutputStream), true); - final BufferedReader in = new BufferedReader(new InputStreamReader(Assertions.assertDoesNotThrow(clientSocket::getInputStream))); + final BufferedReader in = new BufferedReader( + new InputStreamReader(Assertions.assertDoesNotThrow(clientSocket::getInputStream)) + ); out.print("a"); out.flush(); @@ -78,10 +131,13 @@ void testReceivingOneChar() { @Test void testReceivingThreeChars() { this.countDownLatch = new CountDownLatch(1); - final java.net.Socket clientSocket = Assertions.assertDoesNotThrow(() -> new java.net.Socket("localhost", 9090)); + final java.net.Socket clientSocket = Assertions + .assertDoesNotThrow(() -> new java.net.Socket("localhost", 9090)); final PrintWriter out = new PrintWriter(Assertions.assertDoesNotThrow(clientSocket::getOutputStream), true); - final BufferedReader in = new BufferedReader(new InputStreamReader(Assertions.assertDoesNotThrow(clientSocket::getInputStream))); + final BufferedReader in = new BufferedReader( + new InputStreamReader(Assertions.assertDoesNotThrow(clientSocket::getInputStream)) + ); out.print("a"); out.flush(); diff --git a/src/test/java/com/teragrep/net_01/channel/server/ServerSendingTest.java b/src/test/java/com/teragrep/net_01/channel/server/ServerSendingTest.java index d42676f..e0e6466 100644 --- a/src/test/java/com/teragrep/net_01/channel/server/ServerSendingTest.java +++ b/src/test/java/com/teragrep/net_01/channel/server/ServerSendingTest.java @@ -1,10 +1,54 @@ +/* + * Java Zero Copy Networking Library net_01 + * Copyright (C) 2024 Suomen Kanuuna Oy + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * + * Additional permission under GNU Affero General Public License version 3 + * section 7 + * + * If you modify this Program, or any covered work, by linking or combining it + * with other code, such other code is not for that reason alone subject to any + * of the requirements of the GNU Affero GPL version 3 as long as this Program + * is the same Program as licensed from Suomen Kanuuna Oy without any additional + * modifications. + * + * Supplemented terms under GNU Affero General Public License version 3 + * section 7 + * + * Origin of the software must be attributed to Suomen Kanuuna Oy. Any modified + * versions must be marked as "Modified version of" The Program. + * + * Names of the licensors and authors may not be used for publicity purposes. + * + * No rights are granted for use of trade names, trademarks, or service marks + * which are in The Program if any. + * + * Licensee must indemnify licensors and authors for any liability that these + * contractual assumptions impose on licensors and authors. + * + * To the extent this program is licensed as part of the Commercial versions of + * Teragrep, the applicable Commercial License may apply to this file if you as + * a licensee so wish it. + */ package com.teragrep.net_01.channel.server; import com.teragrep.buf_01.buffer.lease.MemorySegmentLeaseStub; import com.teragrep.buf_01.buffer.pool.OpeningPool; import com.teragrep.buf_01.buffer.supply.ArenaMemorySegmentLeaseSupplier; import com.teragrep.net_01.channel.context.ClockFactory; -import com.teragrep.net_01.channel.context.ConsumingClockFactory; import com.teragrep.net_01.channel.context.SendingClockFactory; import com.teragrep.net_01.channel.socket.PlainFactory; import com.teragrep.net_01.channel.socket.SocketFactory; @@ -19,21 +63,23 @@ import java.io.InputStreamReader; import java.io.PrintWriter; import java.lang.foreign.Arena; -import java.util.ArrayList; -import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executors; @TestInstance(TestInstance.Lifecycle.PER_CLASS) public final class ServerSendingTest { + private Server server; private CountDownLatch countDownLatch; private OpeningPool pool; + @BeforeAll void beforeAll() { final EventLoopFactory eventLoopFactory = new EventLoopFactory(); final SocketFactory socketFactory = new PlainFactory(); - this.pool = new OpeningPool(new UnboundPool<>(new ArenaMemorySegmentLeaseSupplier(Arena.ofShared(), 128), new MemorySegmentLeaseStub())); + this.pool = new OpeningPool( + new UnboundPool<>(new ArenaMemorySegmentLeaseSupplier(Arena.ofShared(), 128), new MemorySegmentLeaseStub()) + ); final ClockFactory clockFactory = new SendingClockFactory((msgStr) -> countDownLatch.countDown(), pool); final EventLoop el = Assertions.assertDoesNotThrow(eventLoopFactory::create); @@ -42,8 +88,12 @@ void beforeAll() { final Thread elT = new Thread(el); elT.start(); - final ServerFactory serverFactory = new ServerFactory(el, - Executors.newSingleThreadExecutor(), socketFactory, clockFactory); + final ServerFactory serverFactory = new ServerFactory( + el, + Executors.newSingleThreadExecutor(), + socketFactory, + clockFactory + ); this.server = Assertions.assertDoesNotThrow(() -> serverFactory.create(9090)); } @@ -57,10 +107,13 @@ void afterAll() { @Test void testSending() { this.countDownLatch = new CountDownLatch(1); - final java.net.Socket clientSocket = Assertions.assertDoesNotThrow(() -> new java.net.Socket("localhost", 9090)); + final java.net.Socket clientSocket = Assertions + .assertDoesNotThrow(() -> new java.net.Socket("localhost", 9090)); final PrintWriter out = new PrintWriter(Assertions.assertDoesNotThrow(clientSocket::getOutputStream), true); - final BufferedReader in = new BufferedReader(new InputStreamReader(Assertions.assertDoesNotThrow(clientSocket::getInputStream))); + final BufferedReader in = new BufferedReader( + new InputStreamReader(Assertions.assertDoesNotThrow(clientSocket::getInputStream)) + ); final String request = "Hello world! This is some input"; out.println(request); out.flush(); diff --git a/src/test/java/com/teragrep/net_01/channel/socket/SocketFake.java b/src/test/java/com/teragrep/net_01/channel/socket/SocketFake.java index b5ba826..fd56c69 100644 --- a/src/test/java/com/teragrep/net_01/channel/socket/SocketFake.java +++ b/src/test/java/com/teragrep/net_01/channel/socket/SocketFake.java @@ -47,7 +47,6 @@ import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; -import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; import java.util.Collections; import java.util.List; diff --git a/src/test/java/com/teragrep/net_01/channel/socket/SocketTest.java b/src/test/java/com/teragrep/net_01/channel/socket/SocketTest.java index c66b113..d98ee7f 100644 --- a/src/test/java/com/teragrep/net_01/channel/socket/SocketTest.java +++ b/src/test/java/com/teragrep/net_01/channel/socket/SocketTest.java @@ -1,3 +1,48 @@ +/* + * Java Zero Copy Networking Library net_01 + * Copyright (C) 2024 Suomen Kanuuna Oy + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * + * Additional permission under GNU Affero General Public License version 3 + * section 7 + * + * If you modify this Program, or any covered work, by linking or combining it + * with other code, such other code is not for that reason alone subject to any + * of the requirements of the GNU Affero GPL version 3 as long as this Program + * is the same Program as licensed from Suomen Kanuuna Oy without any additional + * modifications. + * + * Supplemented terms under GNU Affero General Public License version 3 + * section 7 + * + * Origin of the software must be attributed to Suomen Kanuuna Oy. Any modified + * versions must be marked as "Modified version of" The Program. + * + * Names of the licensors and authors may not be used for publicity purposes. + * + * No rights are granted for use of trade names, trademarks, or service marks + * which are in The Program if any. + * + * Licensee must indemnify licensors and authors for any liability that these + * contractual assumptions impose on licensors and authors. + * + * To the extent this program is licensed as part of the Commercial versions of + * Teragrep, the applicable Commercial License may apply to this file if you as + * a licensee so wish it. + */ package com.teragrep.net_01.channel.socket; import com.teragrep.buf_01.buffer.lease.MemorySegmentLeaseStub; @@ -16,7 +61,6 @@ import java.lang.foreign.MemorySegment; import java.lang.foreign.ValueLayout; import java.net.InetSocketAddress; -import java.nio.ByteBuffer; import java.nio.channels.ServerSocketChannel; import java.nio.charset.StandardCharsets; import java.util.ArrayList; @@ -26,11 +70,14 @@ @TestInstance(TestInstance.Lifecycle.PER_CLASS) public final class SocketTest { + private OpeningPool pool; @BeforeAll void beforeAll() { - this.pool = new OpeningPool(new UnboundPool<>(new ArenaMemorySegmentLeaseSupplier(Arena.ofShared(), 128), new MemorySegmentLeaseStub())); + this.pool = new OpeningPool( + new UnboundPool<>(new ArenaMemorySegmentLeaseSupplier(Arena.ofShared(), 128), new MemorySegmentLeaseStub()) + ); } @AfterAll @@ -66,7 +113,9 @@ void testPlainSocketWrite() { // Init client final java.net.Socket clientSocket = new java.net.Socket("localhost", 9090); - final BufferedReader in = new BufferedReader(new InputStreamReader(Assertions.assertDoesNotThrow(clientSocket::getInputStream))); + final BufferedReader in = new BufferedReader( + new InputStreamReader(Assertions.assertDoesNotThrow(clientSocket::getInputStream)) + ); // Init PlainSocket final Socket socket = new PlainSocket(socketCh.accept()); @@ -145,7 +194,6 @@ private List stringToBuffer(final String str) { } } - System.out.println("stringToBuffer"); leases.forEach(l -> { System.out.println(Arrays.toString(l.leasedObject().toArray(ValueLayout.JAVA_BYTE))); From 7ea558ec34724ad37266f668f8360179236ed380 Mon Sep 17 00:00:00 2001 From: eemhu <125959687+eemhu@users.noreply.github.com> Date: Wed, 8 Apr 2026 14:22:37 +0300 Subject: [PATCH 21/45] change method names to better ones in TrackedMemorySegmentLease --- .../buffer/TrackedMemorySegmentLease.java | 18 +++++++----------- .../buffer/TrackedMemorySegmentLeaseTest.java | 6 +++--- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/teragrep/net_01/channel/buffer/TrackedMemorySegmentLease.java b/src/main/java/com/teragrep/net_01/channel/buffer/TrackedMemorySegmentLease.java index 15baba8..10ae381 100644 --- a/src/main/java/com/teragrep/net_01/channel/buffer/TrackedMemorySegmentLease.java +++ b/src/main/java/com/teragrep/net_01/channel/buffer/TrackedMemorySegmentLease.java @@ -144,28 +144,24 @@ public void write(final byte b) { origin.leasedObject().set(ValueLayout.JAVA_BYTE, nextIndex, b); } - public long position() { + public long currentPosition() { return currentOffset.get(); } - public void position(long pos) { - currentOffset.set(pos); + public void position(final long newPosition) { + currentOffset.set(newPosition); } - public long limit() { + public long currentLimit() { return limit.get(); } - public void limit(long newLimit) { - limit.set(newLimit); - } - - public long limit(int index) { - if (index < 0 || index > leasedObject().byteSize()) { + public long limit(final long newLimit) { + if (newLimit < 0 || newLimit > leasedObject().byteSize()) { throw new IndexOutOfBoundsException("Out of bounds"); } - limit.set(index); + limit.set(newLimit); return limit.get(); } } diff --git a/src/test/java/com/teragrep/net_01/channel/context/buffer/TrackedMemorySegmentLeaseTest.java b/src/test/java/com/teragrep/net_01/channel/context/buffer/TrackedMemorySegmentLeaseTest.java index 099ee4f..e08776c 100644 --- a/src/test/java/com/teragrep/net_01/channel/context/buffer/TrackedMemorySegmentLeaseTest.java +++ b/src/test/java/com/teragrep/net_01/channel/context/buffer/TrackedMemorySegmentLeaseTest.java @@ -64,11 +64,11 @@ void testProgressing() { ); final TrackedMemorySegmentLease trackedLease = new TrackedMemorySegmentLease(pool.get()); - Assertions.assertEquals(0L, trackedLease.position()); + Assertions.assertEquals(0L, trackedLease.currentPosition()); int loops = 0; for (int i = 0; i < 5; i++) { - Assertions.assertEquals(i, trackedLease.position()); + Assertions.assertEquals(i, trackedLease.currentPosition()); Assertions.assertTrue(trackedLease.hasNext()); Assertions.assertEquals((byte) 0, trackedLease.next()); loops++; @@ -77,6 +77,6 @@ void testProgressing() { Assertions.assertFalse(trackedLease.hasNext()); Assertions.assertThrows(IndexOutOfBoundsException.class, trackedLease::next); - Assertions.assertEquals(5L, trackedLease.position()); + Assertions.assertEquals(5L, trackedLease.currentPosition()); } } From bb88473a754454098d35836edf897cf8b6ddfc69 Mon Sep 17 00:00:00 2001 From: eemhu <125959687+eemhu@users.noreply.github.com> Date: Wed, 8 Apr 2026 14:23:07 +0300 Subject: [PATCH 22/45] remove return value from limit method in TrackedMemorySegmentLease --- .../net_01/channel/buffer/TrackedMemorySegmentLease.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/com/teragrep/net_01/channel/buffer/TrackedMemorySegmentLease.java b/src/main/java/com/teragrep/net_01/channel/buffer/TrackedMemorySegmentLease.java index 10ae381..8cf3754 100644 --- a/src/main/java/com/teragrep/net_01/channel/buffer/TrackedMemorySegmentLease.java +++ b/src/main/java/com/teragrep/net_01/channel/buffer/TrackedMemorySegmentLease.java @@ -156,12 +156,11 @@ public long currentLimit() { return limit.get(); } - public long limit(final long newLimit) { + public void limit(final long newLimit) { if (newLimit < 0 || newLimit > leasedObject().byteSize()) { throw new IndexOutOfBoundsException("Out of bounds"); } limit.set(newLimit); - return limit.get(); } } From 6c6541124085ad65b242f4c47c1206afb8936a40 Mon Sep 17 00:00:00 2001 From: eemhu <125959687+eemhu@users.noreply.github.com> Date: Wed, 8 Apr 2026 14:26:55 +0300 Subject: [PATCH 23/45] add checks for Out of bounds in TrackedMemorySegmentLease --- .../channel/buffer/TrackedMemorySegmentLease.java | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/teragrep/net_01/channel/buffer/TrackedMemorySegmentLease.java b/src/main/java/com/teragrep/net_01/channel/buffer/TrackedMemorySegmentLease.java index 8cf3754..1171a94 100644 --- a/src/main/java/com/teragrep/net_01/channel/buffer/TrackedMemorySegmentLease.java +++ b/src/main/java/com/teragrep/net_01/channel/buffer/TrackedMemorySegmentLease.java @@ -149,6 +149,13 @@ public long currentPosition() { } public void position(final long newPosition) { + final long segmentByteSize = leasedObject().byteSize(); + if (newPosition < 0 || newPosition > segmentByteSize) { + throw new IndexOutOfBoundsException( + "New position was out of bounds; expected value between 0 and " + segmentByteSize + "; was " + + newPosition + ); + } currentOffset.set(newPosition); } @@ -157,8 +164,12 @@ public long currentLimit() { } public void limit(final long newLimit) { - if (newLimit < 0 || newLimit > leasedObject().byteSize()) { - throw new IndexOutOfBoundsException("Out of bounds"); + final long segmentByteSize = leasedObject().byteSize(); + if (newLimit < -1 || newLimit > segmentByteSize) { + throw new IndexOutOfBoundsException( + "New limit was out of bounds; expected value between -1 and " + segmentByteSize + "; was " + + newLimit + ); } limit.set(newLimit); From 1107873593173f2ce494d3c1165314e0a1cdcf0d Mon Sep 17 00:00:00 2001 From: eemhu <125959687+eemhu@users.noreply.github.com> Date: Fri, 10 Apr 2026 15:13:55 +0300 Subject: [PATCH 24/45] remove boxed Byte from TrackedMemorySegmentLease --- .../net_01/channel/buffer/TrackedMemorySegmentLease.java | 7 ++----- .../com/teragrep/net_01/channel/context/SendingClock.java | 2 +- .../com/teragrep/net_01/channel/socket/SocketTest.java | 2 +- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/teragrep/net_01/channel/buffer/TrackedMemorySegmentLease.java b/src/main/java/com/teragrep/net_01/channel/buffer/TrackedMemorySegmentLease.java index 1171a94..a3e52cf 100644 --- a/src/main/java/com/teragrep/net_01/channel/buffer/TrackedMemorySegmentLease.java +++ b/src/main/java/com/teragrep/net_01/channel/buffer/TrackedMemorySegmentLease.java @@ -49,10 +49,9 @@ import java.lang.foreign.MemorySegment; import java.lang.foreign.ValueLayout; -import java.util.Iterator; import java.util.concurrent.atomic.AtomicLong; -public class TrackedMemorySegmentLease implements Lease, Iterator { +public class TrackedMemorySegmentLease implements Lease { private final Lease origin; private final AtomicLong currentOffset; @@ -111,7 +110,6 @@ public void close() throws Exception { origin.close(); } - @Override public boolean hasNext() { final boolean rv; if (limit.get() == -1) { @@ -124,8 +122,7 @@ public boolean hasNext() { return rv; } - @Override - public Byte next() { + public byte next() { if (!hasNext()) { throw new IndexOutOfBoundsException("Reached end of segment or limit, cannot provide next byte"); } diff --git a/src/test/java/com/teragrep/net_01/channel/context/SendingClock.java b/src/test/java/com/teragrep/net_01/channel/context/SendingClock.java index 8e7bf35..f1018f1 100644 --- a/src/test/java/com/teragrep/net_01/channel/context/SendingClock.java +++ b/src/test/java/com/teragrep/net_01/channel/context/SendingClock.java @@ -68,7 +68,7 @@ public SendingClock(final EstablishedContext ctx, final Consumer consume public void advance(final TrackedMemorySegmentLease bufferLease) { final StringBuilder stringBuilder = new StringBuilder(); while (bufferLease.hasNext()) { - final char c = (char) bufferLease.next().byteValue(); + final char c = (char) bufferLease.next(); stringBuilder.append(c); } diff --git a/src/test/java/com/teragrep/net_01/channel/socket/SocketTest.java b/src/test/java/com/teragrep/net_01/channel/socket/SocketTest.java index d98ee7f..10db124 100644 --- a/src/test/java/com/teragrep/net_01/channel/socket/SocketTest.java +++ b/src/test/java/com/teragrep/net_01/channel/socket/SocketTest.java @@ -163,7 +163,7 @@ private String bufferToString(final List leases) { final StringBuilder stringBuilder = new StringBuilder(); for (final TrackedMemorySegmentLease buf : leases) { while (buf.hasNext()) { - stringBuilder.append((char) buf.next().byteValue()); + stringBuilder.append((char) buf.next()); } } return stringBuilder.toString(); From 35d58794e298757b6f24e33bcabc6ba387cbb2de Mon Sep 17 00:00:00 2001 From: eemhu <125959687+eemhu@users.noreply.github.com> Date: Tue, 21 Apr 2026 09:24:18 +0300 Subject: [PATCH 25/45] change to use buf_01 version of TrackedMemorySegmentLease --- .../buffer/TrackedMemorySegmentLease.java | 174 ------------------ .../channel/buffer/writable/Writeable.java | 5 +- .../buffer/writable/WriteableAccess.java | 6 +- .../buffer/writable/WriteableClosure.java | 6 +- .../writable/WriteableInvalidation.java | 7 +- .../buffer/writable/WriteableLeaseful.java | 5 +- .../buffer/writable/WriteableStub.java | 5 +- .../channel/buffer/writable/Writeables.java | 8 +- .../net_01/channel/context/Clock.java | 6 +- .../net_01/channel/context/EgressImpl.java | 5 +- .../net_01/channel/context/IngressImpl.java | 9 +- .../net_01/channel/socket/PlainSocket.java | 20 +- .../net_01/channel/socket/ReadResult.java | 11 +- .../net_01/channel/socket/Socket.java | 11 +- .../net_01/channel/socket/TLSSocket.java | 7 +- .../net_01/channel/socket/WrittenResult.java | 11 +- .../net_01/channel/StringToLease.java | 7 +- .../channel/context/ConsumingClock.java | 5 +- .../net_01/channel/context/SendingClock.java | 5 +- .../channel/context/StringWriteable.java | 13 +- .../buffer/TrackedMemorySegmentLeaseTest.java | 6 +- .../net_01/channel/socket/SocketFake.java | 7 +- .../net_01/channel/socket/SocketTest.java | 21 ++- 23 files changed, 107 insertions(+), 253 deletions(-) delete mode 100644 src/main/java/com/teragrep/net_01/channel/buffer/TrackedMemorySegmentLease.java diff --git a/src/main/java/com/teragrep/net_01/channel/buffer/TrackedMemorySegmentLease.java b/src/main/java/com/teragrep/net_01/channel/buffer/TrackedMemorySegmentLease.java deleted file mode 100644 index a3e52cf..0000000 --- a/src/main/java/com/teragrep/net_01/channel/buffer/TrackedMemorySegmentLease.java +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Java Zero Copy Networking Library net_01 - * Copyright (C) 2024 Suomen Kanuuna Oy - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - * - * Additional permission under GNU Affero General Public License version 3 - * section 7 - * - * If you modify this Program, or any covered work, by linking or combining it - * with other code, such other code is not for that reason alone subject to any - * of the requirements of the GNU Affero GPL version 3 as long as this Program - * is the same Program as licensed from Suomen Kanuuna Oy without any additional - * modifications. - * - * Supplemented terms under GNU Affero General Public License version 3 - * section 7 - * - * Origin of the software must be attributed to Suomen Kanuuna Oy. Any modified - * versions must be marked as "Modified version of" The Program. - * - * Names of the licensors and authors may not be used for publicity purposes. - * - * No rights are granted for use of trade names, trademarks, or service marks - * which are in The Program if any. - * - * Licensee must indemnify licensors and authors for any liability that these - * contractual assumptions impose on licensors and authors. - * - * To the extent this program is licensed as part of the Commercial versions of - * Teragrep, the applicable Commercial License may apply to this file if you as - * a licensee so wish it. - */ -package com.teragrep.net_01.channel.buffer; - -import com.teragrep.buf_01.buffer.lease.Lease; - -import java.lang.foreign.MemorySegment; -import java.lang.foreign.ValueLayout; -import java.util.concurrent.atomic.AtomicLong; - -public class TrackedMemorySegmentLease implements Lease { - - private final Lease origin; - private final AtomicLong currentOffset; - private final AtomicLong limit; - - public TrackedMemorySegmentLease(final Lease origin) { - this(origin, new AtomicLong(0L)); - } - - public TrackedMemorySegmentLease(final Lease origin, final AtomicLong currentOffset) { - this(origin, currentOffset, new AtomicLong(-1L)); - } - - public TrackedMemorySegmentLease( - final Lease origin, - final AtomicLong currentOffset, - final AtomicLong limit - ) { - this.origin = origin; - this.currentOffset = currentOffset; - this.limit = limit; - } - - @Override - public long id() { - return origin.id(); - } - - @Override - public long refs() { - return origin.refs(); - } - - @Override - public MemorySegment leasedObject() { - return origin.leasedObject(); - } - - @Override - public boolean hasZeroRefs() { - return origin.hasZeroRefs(); - } - - @Override - public Lease sliceAt(final long offset) { - return origin.sliceAt(offset); - } - - @Override - public boolean isStub() { - return origin.isStub(); - } - - @Override - public void close() throws Exception { - origin.close(); - } - - public boolean hasNext() { - final boolean rv; - if (limit.get() == -1) { - // limit not set, ignore - rv = currentOffset.get() < origin.leasedObject().byteSize(); - } - else { - rv = currentOffset.get() < Math.min(limit.get(), origin.leasedObject().byteSize()); - } - return rv; - } - - public byte next() { - if (!hasNext()) { - throw new IndexOutOfBoundsException("Reached end of segment or limit, cannot provide next byte"); - } - final long nextIndex = currentOffset.getAndIncrement(); - - return origin.leasedObject().get(ValueLayout.JAVA_BYTE, nextIndex); - } - - public void write(final byte b) { - if (!hasNext()) { - throw new IndexOutOfBoundsException("Reached end of segment or limit, cannot write to next byte"); - } - - final long nextIndex = currentOffset.getAndIncrement(); - - origin.leasedObject().set(ValueLayout.JAVA_BYTE, nextIndex, b); - } - - public long currentPosition() { - return currentOffset.get(); - } - - public void position(final long newPosition) { - final long segmentByteSize = leasedObject().byteSize(); - if (newPosition < 0 || newPosition > segmentByteSize) { - throw new IndexOutOfBoundsException( - "New position was out of bounds; expected value between 0 and " + segmentByteSize + "; was " - + newPosition - ); - } - currentOffset.set(newPosition); - } - - public long currentLimit() { - return limit.get(); - } - - public void limit(final long newLimit) { - final long segmentByteSize = leasedObject().byteSize(); - if (newLimit < -1 || newLimit > segmentByteSize) { - throw new IndexOutOfBoundsException( - "New limit was out of bounds; expected value between -1 and " + segmentByteSize + "; was " - + newLimit - ); - } - - limit.set(newLimit); - } -} diff --git a/src/main/java/com/teragrep/net_01/channel/buffer/writable/Writeable.java b/src/main/java/com/teragrep/net_01/channel/buffer/writable/Writeable.java index 2298cbf..2018032 100644 --- a/src/main/java/com/teragrep/net_01/channel/buffer/writable/Writeable.java +++ b/src/main/java/com/teragrep/net_01/channel/buffer/writable/Writeable.java @@ -45,9 +45,10 @@ */ package com.teragrep.net_01.channel.buffer.writable; -import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; +import com.teragrep.buf_01.buffer.lease.TrackedLease; import java.io.Closeable; +import java.lang.foreign.MemorySegment; import java.util.List; public interface Writeable extends Closeable { @@ -55,7 +56,7 @@ public interface Writeable extends Closeable { @Override void close(); - List memorySegmentLeases(); + List> memorySegmentLeases(); boolean hasRemaining(); diff --git a/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableAccess.java b/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableAccess.java index e0b0fde..78cb506 100644 --- a/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableAccess.java +++ b/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableAccess.java @@ -45,10 +45,12 @@ */ package com.teragrep.net_01.channel.buffer.writable; -import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; +import com.teragrep.buf_01.buffer.lease.TrackedLease; +import com.teragrep.buf_01.buffer.lease.TrackedMemorySegmentLease; import com.teragrep.net_01.channel.buffer.access.Access; import com.teragrep.net_01.channel.buffer.access.Lease; +import java.lang.foreign.MemorySegment; import java.util.List; public final class WriteableAccess implements Writeable { @@ -62,7 +64,7 @@ public WriteableAccess(Writeable writeable, Access access) { } @Override - public List memorySegmentLeases() { + public List> memorySegmentLeases() { // FIXME just not right try (Lease ignored = access.get()) { return writeable.memorySegmentLeases(); diff --git a/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableClosure.java b/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableClosure.java index 6b3c4d7..22f4895 100644 --- a/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableClosure.java +++ b/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableClosure.java @@ -45,11 +45,13 @@ */ package com.teragrep.net_01.channel.buffer.writable; -import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; +import com.teragrep.buf_01.buffer.lease.TrackedLease; +import com.teragrep.buf_01.buffer.lease.TrackedMemorySegmentLease; import com.teragrep.net_01.channel.context.EstablishedContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.lang.foreign.MemorySegment; import java.util.List; /** @@ -82,7 +84,7 @@ public void close() { } @Override - public List memorySegmentLeases() { + public List> memorySegmentLeases() { return writeable.memorySegmentLeases(); } diff --git a/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableInvalidation.java b/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableInvalidation.java index 082b674..ec9c4b7 100644 --- a/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableInvalidation.java +++ b/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableInvalidation.java @@ -45,8 +45,9 @@ */ package com.teragrep.net_01.channel.buffer.writable; -import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; +import com.teragrep.buf_01.buffer.lease.TrackedLease; +import java.lang.foreign.MemorySegment; import java.nio.ByteBuffer; import java.util.List; @@ -65,7 +66,7 @@ public WriteableInvalidation(Writeable writeable) { @Override public void close() { - for (final TrackedMemorySegmentLease lease : memorySegmentLeases()) { + for (final TrackedLease lease : memorySegmentLeases()) { try { lease.close(); } @@ -77,7 +78,7 @@ public void close() { } @Override - public List memorySegmentLeases() { + public List> memorySegmentLeases() { return writeable.memorySegmentLeases(); } diff --git a/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableLeaseful.java b/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableLeaseful.java index 36748a2..dd23d98 100644 --- a/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableLeaseful.java +++ b/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableLeaseful.java @@ -46,7 +46,8 @@ package com.teragrep.net_01.channel.buffer.writable; import com.teragrep.buf_01.buffer.lease.OpenableLease; -import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; +import com.teragrep.buf_01.buffer.lease.TrackedLease; +import com.teragrep.buf_01.buffer.lease.TrackedMemorySegmentLease; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -66,7 +67,7 @@ public WriteableLeaseful(Writeable writeable, List> } @Override - public List memorySegmentLeases() { + public List> memorySegmentLeases() { return writeable.memorySegmentLeases(); } diff --git a/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableStub.java b/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableStub.java index ff96133..d37daf8 100644 --- a/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableStub.java +++ b/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableStub.java @@ -45,14 +45,15 @@ */ package com.teragrep.net_01.channel.buffer.writable; -import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; +import com.teragrep.buf_01.buffer.lease.TrackedLease; +import java.lang.foreign.MemorySegment; import java.util.List; public final class WriteableStub implements Writeable { @Override - public List memorySegmentLeases() { + public List> memorySegmentLeases() { throw new UnsupportedOperationException("WriteableStub does not allow this method"); } diff --git a/src/main/java/com/teragrep/net_01/channel/buffer/writable/Writeables.java b/src/main/java/com/teragrep/net_01/channel/buffer/writable/Writeables.java index 8df719b..fdb46c4 100644 --- a/src/main/java/com/teragrep/net_01/channel/buffer/writable/Writeables.java +++ b/src/main/java/com/teragrep/net_01/channel/buffer/writable/Writeables.java @@ -45,8 +45,10 @@ */ package com.teragrep.net_01.channel.buffer.writable; -import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; +import com.teragrep.buf_01.buffer.lease.TrackedLease; +import com.teragrep.buf_01.buffer.lease.TrackedMemorySegmentLease; +import java.lang.foreign.MemorySegment; import java.util.ArrayList; import java.util.List; @@ -59,7 +61,7 @@ public Writeables(Writeable ... writeables) { } @Override - public List memorySegmentLeases() { + public List> memorySegmentLeases() { long totalBuffers = 0; for (Writeable writeable : writeables) { totalBuffers = totalBuffers + writeable.memorySegmentLeases().size(); @@ -71,7 +73,7 @@ public List memorySegmentLeases() { ); } - List bufferArray = new ArrayList<>((int) totalBuffers); + List> bufferArray = new ArrayList<>((int) totalBuffers); for (final Writeable writeable : writeables) { bufferArray.addAll(writeable.memorySegmentLeases()); } diff --git a/src/main/java/com/teragrep/net_01/channel/context/Clock.java b/src/main/java/com/teragrep/net_01/channel/context/Clock.java index d1bfca0..ad2861d 100644 --- a/src/main/java/com/teragrep/net_01/channel/context/Clock.java +++ b/src/main/java/com/teragrep/net_01/channel/context/Clock.java @@ -45,7 +45,9 @@ */ package com.teragrep.net_01.channel.context; -import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; +import com.teragrep.buf_01.buffer.lease.TrackedLease; + +import java.lang.foreign.MemorySegment; public interface Clock extends AutoCloseable { @@ -53,5 +55,5 @@ public interface Clock extends AutoCloseable { * @param bufferLease to be consumed by the Clock. Clock or it's subsequent actions must close all BufferLease's it * receives otherwise encapsulated buffers are not reusable and memory allocator consumes time. */ - void advance(TrackedMemorySegmentLease bufferLease); + void advance(TrackedLease bufferLease); } diff --git a/src/main/java/com/teragrep/net_01/channel/context/EgressImpl.java b/src/main/java/com/teragrep/net_01/channel/context/EgressImpl.java index b121545..5d35488 100644 --- a/src/main/java/com/teragrep/net_01/channel/context/EgressImpl.java +++ b/src/main/java/com/teragrep/net_01/channel/context/EgressImpl.java @@ -45,7 +45,7 @@ */ package com.teragrep.net_01.channel.context; -import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; +import com.teragrep.buf_01.buffer.lease.TrackedLease; import com.teragrep.net_01.channel.buffer.writable.Writeable; import com.teragrep.net_01.channel.buffer.writable.WriteableStub; import com.teragrep.net_01.channel.socket.WrittenResult; @@ -56,6 +56,7 @@ import java.io.IOException; +import java.lang.foreign.MemorySegment; import java.nio.channels.CancelledKeyException; import java.util.ArrayList; import java.util.Iterator; @@ -165,7 +166,7 @@ public void accept(Writeable writeable) { private void transmit(final List toWriteList) throws IOException { try { - final List writeBuffers = new ArrayList<>(); + final List> writeBuffers = new ArrayList<>(); for (final Writeable w : toWriteList) { writeBuffers.addAll(w.memorySegmentLeases()); diff --git a/src/main/java/com/teragrep/net_01/channel/context/IngressImpl.java b/src/main/java/com/teragrep/net_01/channel/context/IngressImpl.java index de13a10..159fd12 100644 --- a/src/main/java/com/teragrep/net_01/channel/context/IngressImpl.java +++ b/src/main/java/com/teragrep/net_01/channel/context/IngressImpl.java @@ -46,8 +46,9 @@ package com.teragrep.net_01.channel.context; import com.teragrep.buf_01.buffer.lease.OpenableLease; +import com.teragrep.buf_01.buffer.lease.TrackedLease; +import com.teragrep.buf_01.buffer.lease.TrackedMemorySegmentLease; import com.teragrep.buf_01.buffer.pool.LeaseMultiGet; -import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; import com.teragrep.net_01.channel.socket.ReadResult; import com.teragrep.poj_01.pool.Pool; import org.slf4j.Logger; @@ -74,7 +75,7 @@ final class IngressImpl implements Ingress { private final EstablishedContextImpl establishedContext; private final Pool> memorySegmentLeasePool; - private final List activeBuffers; + private final List> activeBuffers; private final Lock lock; // tls public final AtomicBoolean needWrite; @@ -115,7 +116,7 @@ public void run() { System.out.println("activeBuffers.isEmpty=" + activeBuffers.isEmpty()); while (!activeBuffers.isEmpty()) { // IMPORTANT: current tls implementation will skip bytes if BufferLeases are not fully consumed. - TrackedMemorySegmentLease bufferLease = activeBuffers.removeFirst(); + TrackedLease bufferLease = activeBuffers.removeFirst(); LOGGER .debug( "submitting buffer <{}> from activeBuffers <{}> to relpFrame", bufferLease, @@ -234,7 +235,7 @@ private long readData() throws IOException { List> bufferLeases = new LeaseMultiGet(memorySegmentLeasePool).get(4); - List trackedMemorySegmentLeases = new LinkedList<>(); + List> trackedMemorySegmentLeases = new LinkedList<>(); for (OpenableLease bufferLease : bufferLeases) { if (bufferLease.isStub()) { continue; diff --git a/src/main/java/com/teragrep/net_01/channel/socket/PlainSocket.java b/src/main/java/com/teragrep/net_01/channel/socket/PlainSocket.java index 5c6a364..f902317 100644 --- a/src/main/java/com/teragrep/net_01/channel/socket/PlainSocket.java +++ b/src/main/java/com/teragrep/net_01/channel/socket/PlainSocket.java @@ -45,9 +45,11 @@ */ package com.teragrep.net_01.channel.socket; -import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; +import com.teragrep.buf_01.buffer.lease.TrackedLease; +import com.teragrep.buf_01.buffer.lease.TrackedMemorySegmentLease; import java.io.IOException; +import java.lang.foreign.MemorySegment; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; import java.util.ArrayList; @@ -66,8 +68,8 @@ final class PlainSocket implements Socket { } @Override - public ReadResult read(List srcs) throws IOException { - final List rv = new ArrayList<>(srcs.size()); + public ReadResult read(List> srcs) throws IOException { + final List> rv = new ArrayList<>(srcs.size()); final List byteBuffers = new ArrayList<>(srcs.size()); srcs.forEach(src -> { byteBuffers.add(src.leasedObject().asByteBuffer()); @@ -77,7 +79,7 @@ public ReadResult read(List srcs) throws IOException long bytesLeft = readBytes; boolean allRead = false; - for (final TrackedMemorySegmentLease bufferLease : srcs) { + for (final TrackedLease bufferLease : srcs) { final long byteSize = bufferLease.leasedObject().byteSize(); if (!allRead && readBytes > 0) { @@ -87,7 +89,7 @@ public ReadResult read(List srcs) throws IOException // mem.segment bigger than bytes left. // set limit to read amount. final long limit = byteSize - Math.abs(diff); - rv.add(new TrackedMemorySegmentLease(bufferLease, new AtomicLong(0L), new AtomicLong(limit))); + rv.add(new TrackedMemorySegmentLease(bufferLease, 0L, limit)); } else { //else: full mem.segment used, no need to set limit. @@ -118,11 +120,11 @@ public ReadResult read(List srcs) throws IOException } @Override - public WrittenResult write(List leases) throws IOException { + public WrittenResult write(List> leases) throws IOException { final List buffersToWrite = new ArrayList<>(leases.size()); - final List rv = new ArrayList<>(leases.size()); + final List> rv = new ArrayList<>(leases.size()); - for (final TrackedMemorySegmentLease lease : leases) { + for (final TrackedLease lease : leases) { buffersToWrite.add(lease.leasedObject().asByteBuffer()); } @@ -131,7 +133,7 @@ public WrittenResult write(List leases) throws IOExce long bytesLeft = bytesWritten; boolean allWritten = false; - for (final TrackedMemorySegmentLease bufferLease : leases) { + for (final TrackedLease bufferLease : leases) { final long byteSize = bufferLease.leasedObject().byteSize(); if (!allWritten && bytesWritten > 0) { diff --git a/src/main/java/com/teragrep/net_01/channel/socket/ReadResult.java b/src/main/java/com/teragrep/net_01/channel/socket/ReadResult.java index fc54de4..c5a10ed 100644 --- a/src/main/java/com/teragrep/net_01/channel/socket/ReadResult.java +++ b/src/main/java/com/teragrep/net_01/channel/socket/ReadResult.java @@ -45,16 +45,17 @@ */ package com.teragrep.net_01.channel.socket; -import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; +import com.teragrep.buf_01.buffer.lease.TrackedLease; +import java.lang.foreign.MemorySegment; import java.util.List; -public final class ReadResult implements IOResult { +public final class ReadResult implements IOResult> { private final long bytesRead; - private final List leases; + private final List> leases; - public ReadResult(final long bytesRead, final List leases) { + public ReadResult(final long bytesRead, final List> leases) { this.bytesRead = bytesRead; this.leases = leases; } @@ -65,7 +66,7 @@ public long bytes() { } @Override - public List leases() { + public List> leases() { return leases; } } diff --git a/src/main/java/com/teragrep/net_01/channel/socket/Socket.java b/src/main/java/com/teragrep/net_01/channel/socket/Socket.java index 2b2bd66..8faebe8 100644 --- a/src/main/java/com/teragrep/net_01/channel/socket/Socket.java +++ b/src/main/java/com/teragrep/net_01/channel/socket/Socket.java @@ -45,9 +45,10 @@ */ package com.teragrep.net_01.channel.socket; -import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; +import com.teragrep.buf_01.buffer.lease.TrackedLease; import java.io.IOException; +import java.lang.foreign.MemorySegment; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; import java.util.List; @@ -60,20 +61,20 @@ public interface Socket { /** * Read data from a network connection. * - * @param dsts {@link ByteBuffer}s which are read to from the connection + * @param srcs {@link TrackedLease}s which are read to from the connection * @return amount of bytes read * @throws IOException if read fails */ - ReadResult read(List srcs) throws IOException; + ReadResult read(List> srcs) throws IOException; /** * Write data through a network connection. * - * @param dsts {@link ByteBuffer}s which are written to the connection + * @param dsts {@link TrackedLease}s which are written to the connection * @return amount of bytes written * @throws IOException if write fails */ - WrittenResult write(List dsts) throws IOException; + WrittenResult write(List> dsts) throws IOException; /** * Provides information about a network connection diff --git a/src/main/java/com/teragrep/net_01/channel/socket/TLSSocket.java b/src/main/java/com/teragrep/net_01/channel/socket/TLSSocket.java index f5e0274..07a4b03 100644 --- a/src/main/java/com/teragrep/net_01/channel/socket/TLSSocket.java +++ b/src/main/java/com/teragrep/net_01/channel/socket/TLSSocket.java @@ -45,10 +45,11 @@ */ package com.teragrep.net_01.channel.socket; -import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; +import com.teragrep.buf_01.buffer.lease.TrackedLease; import tlschannel.TlsChannel; import java.io.IOException; +import java.lang.foreign.MemorySegment; import java.nio.channels.SocketChannel; import java.util.List; @@ -66,13 +67,13 @@ final class TLSSocket implements Socket { } @Override - public ReadResult read(List dsts) throws IOException { + public ReadResult read(List> dsts) throws IOException { throw new UnsupportedOperationException(); //return tlsChannel.read(dsts); } @Override - public WrittenResult write(List dsts) throws IOException { + public WrittenResult write(List> dsts) throws IOException { throw new UnsupportedOperationException(); //return tlsChannel.write(dsts); } diff --git a/src/main/java/com/teragrep/net_01/channel/socket/WrittenResult.java b/src/main/java/com/teragrep/net_01/channel/socket/WrittenResult.java index 585bad0..e198f4f 100644 --- a/src/main/java/com/teragrep/net_01/channel/socket/WrittenResult.java +++ b/src/main/java/com/teragrep/net_01/channel/socket/WrittenResult.java @@ -45,16 +45,17 @@ */ package com.teragrep.net_01.channel.socket; -import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; +import com.teragrep.buf_01.buffer.lease.TrackedLease; +import java.lang.foreign.MemorySegment; import java.util.List; -public class WrittenResult implements IOResult { +public class WrittenResult implements IOResult> { private final long bytesWritten; - private final List leases; + private final List> leases; - public WrittenResult(final long bytesWritten, final List leases) { + public WrittenResult(final long bytesWritten, final List> leases) { this.bytesWritten = bytesWritten; this.leases = leases; } @@ -65,7 +66,7 @@ public long bytes() { } @Override - public List leases() { + public List> leases() { return leases; } } diff --git a/src/test/java/com/teragrep/net_01/channel/StringToLease.java b/src/test/java/com/teragrep/net_01/channel/StringToLease.java index b36003f..ad4f272 100644 --- a/src/test/java/com/teragrep/net_01/channel/StringToLease.java +++ b/src/test/java/com/teragrep/net_01/channel/StringToLease.java @@ -46,9 +46,10 @@ package com.teragrep.net_01.channel; import com.teragrep.buf_01.buffer.lease.OpenableLease; +import com.teragrep.buf_01.buffer.lease.TrackedLease; +import com.teragrep.buf_01.buffer.lease.TrackedMemorySegmentLease; import com.teragrep.buf_01.buffer.pool.LeaseMultiGet; import com.teragrep.buf_01.buffer.pool.OpeningPool; -import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; import com.teragrep.net_01.channel.buffer.writable.Writeable; import com.teragrep.net_01.channel.context.StringWriteable; @@ -70,13 +71,13 @@ public StringToLease(final String origin, OpeningPool pool) { public Writeable toWriteable() { final byte[] bytes = origin.getBytes(StandardCharsets.UTF_8); final List> leases = new LeaseMultiGet(pool).get(bytes.length); - final List trackedLeases = new ArrayList<>(leases.size()); + final List> trackedLeases = new ArrayList<>(leases.size()); for (final OpenableLease lease : leases) { trackedLeases.add(new TrackedMemorySegmentLease(lease)); } int i = 0; - for (final TrackedMemorySegmentLease trackedLease : trackedLeases) { + for (final TrackedLease trackedLease : trackedLeases) { while (trackedLease.hasNext() && i < bytes.length) { trackedLease.write(bytes[i]); i++; diff --git a/src/test/java/com/teragrep/net_01/channel/context/ConsumingClock.java b/src/test/java/com/teragrep/net_01/channel/context/ConsumingClock.java index e89300d..dbf37fb 100644 --- a/src/test/java/com/teragrep/net_01/channel/context/ConsumingClock.java +++ b/src/test/java/com/teragrep/net_01/channel/context/ConsumingClock.java @@ -45,8 +45,9 @@ */ package com.teragrep.net_01.channel.context; -import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; +import com.teragrep.buf_01.buffer.lease.TrackedLease; +import java.lang.foreign.MemorySegment; import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; @@ -62,7 +63,7 @@ public ConsumingClock(final EstablishedContext ctx, final Consumer> m } @Override - public void advance(TrackedMemorySegmentLease lease) { + public void advance(TrackedLease lease) { final List bytes = new ArrayList<>(); while (lease.hasNext()) { bytes.add(lease.next()); diff --git a/src/test/java/com/teragrep/net_01/channel/context/SendingClock.java b/src/test/java/com/teragrep/net_01/channel/context/SendingClock.java index f1018f1..1e4a58e 100644 --- a/src/test/java/com/teragrep/net_01/channel/context/SendingClock.java +++ b/src/test/java/com/teragrep/net_01/channel/context/SendingClock.java @@ -45,11 +45,12 @@ */ package com.teragrep.net_01.channel.context; +import com.teragrep.buf_01.buffer.lease.TrackedLease; import com.teragrep.buf_01.buffer.pool.OpeningPool; import com.teragrep.net_01.channel.StringToLease; -import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; import com.teragrep.net_01.channel.buffer.writable.Writeable; +import java.lang.foreign.MemorySegment; import java.util.function.Consumer; public final class SendingClock implements Clock { @@ -65,7 +66,7 @@ public SendingClock(final EstablishedContext ctx, final Consumer consume } @Override - public void advance(final TrackedMemorySegmentLease bufferLease) { + public void advance(final TrackedLease bufferLease) { final StringBuilder stringBuilder = new StringBuilder(); while (bufferLease.hasNext()) { final char c = (char) bufferLease.next(); diff --git a/src/test/java/com/teragrep/net_01/channel/context/StringWriteable.java b/src/test/java/com/teragrep/net_01/channel/context/StringWriteable.java index 4474de8..087a669 100644 --- a/src/test/java/com/teragrep/net_01/channel/context/StringWriteable.java +++ b/src/test/java/com/teragrep/net_01/channel/context/StringWriteable.java @@ -45,22 +45,23 @@ */ package com.teragrep.net_01.channel.context; -import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; +import com.teragrep.buf_01.buffer.lease.TrackedLease; import com.teragrep.net_01.channel.buffer.writable.Writeable; +import java.lang.foreign.MemorySegment; import java.util.List; public final class StringWriteable implements Writeable { - private final List buffers; + private final List> buffers; - public StringWriteable(final List buffers) { + public StringWriteable(final List> buffers) { this.buffers = buffers; } @Override public void close() { - for (TrackedMemorySegmentLease buf : buffers) { + for (TrackedLease buf : buffers) { try { buf.close(); } @@ -71,14 +72,14 @@ public void close() { } @Override - public List memorySegmentLeases() { + public List> memorySegmentLeases() { return buffers; } @Override public boolean hasRemaining() { boolean rv = false; - for (final TrackedMemorySegmentLease buffer : buffers) { + for (final TrackedLease buffer : buffers) { if (buffer.hasNext()) { rv = true; break; diff --git a/src/test/java/com/teragrep/net_01/channel/context/buffer/TrackedMemorySegmentLeaseTest.java b/src/test/java/com/teragrep/net_01/channel/context/buffer/TrackedMemorySegmentLeaseTest.java index e08776c..a96a453 100644 --- a/src/test/java/com/teragrep/net_01/channel/context/buffer/TrackedMemorySegmentLeaseTest.java +++ b/src/test/java/com/teragrep/net_01/channel/context/buffer/TrackedMemorySegmentLeaseTest.java @@ -46,14 +46,16 @@ package com.teragrep.net_01.channel.context.buffer; import com.teragrep.buf_01.buffer.lease.MemorySegmentLeaseStub; +import com.teragrep.buf_01.buffer.lease.TrackedLease; +import com.teragrep.buf_01.buffer.lease.TrackedMemorySegmentLease; import com.teragrep.buf_01.buffer.pool.OpeningPool; import com.teragrep.buf_01.buffer.supply.ArenaMemorySegmentLeaseSupplier; -import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; import com.teragrep.poj_01.pool.UnboundPool; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; public final class TrackedMemorySegmentLeaseTest { @@ -62,7 +64,7 @@ void testProgressing() { final OpeningPool pool = new OpeningPool( new UnboundPool<>(new ArenaMemorySegmentLeaseSupplier(Arena.ofShared(), 5), new MemorySegmentLeaseStub()) ); - final TrackedMemorySegmentLease trackedLease = new TrackedMemorySegmentLease(pool.get()); + final TrackedLease trackedLease = new TrackedMemorySegmentLease(pool.get()); Assertions.assertEquals(0L, trackedLease.currentPosition()); diff --git a/src/test/java/com/teragrep/net_01/channel/socket/SocketFake.java b/src/test/java/com/teragrep/net_01/channel/socket/SocketFake.java index fd56c69..695a736 100644 --- a/src/test/java/com/teragrep/net_01/channel/socket/SocketFake.java +++ b/src/test/java/com/teragrep/net_01/channel/socket/SocketFake.java @@ -45,8 +45,9 @@ */ package com.teragrep.net_01.channel.socket; -import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; +import com.teragrep.buf_01.buffer.lease.TrackedLease; +import java.lang.foreign.MemorySegment; import java.nio.channels.SocketChannel; import java.util.Collections; import java.util.List; @@ -60,12 +61,12 @@ public SocketFake() { } @Override - public ReadResult read(List dsts) { + public ReadResult read(List> dsts) { return new ReadResult(0, Collections.emptyList()); } @Override - public WrittenResult write(List dsts) { + public WrittenResult write(List> dsts) { return new WrittenResult(0, Collections.emptyList()); } diff --git a/src/test/java/com/teragrep/net_01/channel/socket/SocketTest.java b/src/test/java/com/teragrep/net_01/channel/socket/SocketTest.java index 10db124..5a68682 100644 --- a/src/test/java/com/teragrep/net_01/channel/socket/SocketTest.java +++ b/src/test/java/com/teragrep/net_01/channel/socket/SocketTest.java @@ -47,10 +47,11 @@ import com.teragrep.buf_01.buffer.lease.MemorySegmentLeaseStub; import com.teragrep.buf_01.buffer.lease.OpenableLease; +import com.teragrep.buf_01.buffer.lease.TrackedLease; +import com.teragrep.buf_01.buffer.lease.TrackedMemorySegmentLease; import com.teragrep.buf_01.buffer.pool.LeaseMultiGet; import com.teragrep.buf_01.buffer.pool.OpeningPool; import com.teragrep.buf_01.buffer.supply.ArenaMemorySegmentLeaseSupplier; -import com.teragrep.net_01.channel.buffer.TrackedMemorySegmentLease; import com.teragrep.poj_01.pool.UnboundPool; import org.junit.jupiter.api.*; @@ -148,7 +149,7 @@ void testPlainSocketRead() { out.println("worldHello"); - List bufs = emptyBuffers(10); + List> bufs = emptyBuffers(10); ReadResult res = socket.read(bufs); Assertions.assertEquals("worldHello\n", bufferToString(res.leases())); @@ -159,9 +160,9 @@ void testPlainSocketRead() { }); } - private String bufferToString(final List leases) { + private String bufferToString(final List> leases) { final StringBuilder stringBuilder = new StringBuilder(); - for (final TrackedMemorySegmentLease buf : leases) { + for (final TrackedLease buf : leases) { while (buf.hasNext()) { stringBuilder.append((char) buf.next()); } @@ -169,12 +170,12 @@ private String bufferToString(final List leases) { return stringBuilder.toString(); } - private List stringToBuffer(final String str) { + private List> stringToBuffer(final String str) { final byte[] bytes = str.getBytes(StandardCharsets.UTF_8); - final List leases = emptyBuffers(bytes.length); + final List> leases = emptyBuffers(bytes.length); - Iterator it = leases.iterator(); - TrackedMemorySegmentLease currentLease = it.next(); + Iterator> it = leases.iterator(); + TrackedLease currentLease = it.next(); int currentIndex = 0; long size = currentLease.leasedObject().byteSize(); for (int i = 0; i < bytes.length; i++) { @@ -202,9 +203,9 @@ private List stringToBuffer(final String str) { return leases; } - private List emptyBuffers(int bytes) { + private List> emptyBuffers(int bytes) { final List> leases = new LeaseMultiGet(pool).get(bytes); - final List rv = new ArrayList<>(leases.size()); + final List> rv = new ArrayList<>(leases.size()); leases.forEach(lease -> { rv.add(new TrackedMemorySegmentLease(lease)); From 46e045d15c9e740a9c9e710184e39a4f1c21e6c1 Mon Sep 17 00:00:00 2001 From: eemhu <125959687+eemhu@users.noreply.github.com> Date: Tue, 21 Apr 2026 09:26:11 +0300 Subject: [PATCH 26/45] add read-write impls to TLSSocket --- .../net_01/channel/socket/TLSSocket.java | 101 ++++++++++++++++-- 1 file changed, 95 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/teragrep/net_01/channel/socket/TLSSocket.java b/src/main/java/com/teragrep/net_01/channel/socket/TLSSocket.java index 07a4b03..31d7b15 100644 --- a/src/main/java/com/teragrep/net_01/channel/socket/TLSSocket.java +++ b/src/main/java/com/teragrep/net_01/channel/socket/TLSSocket.java @@ -46,11 +46,14 @@ package com.teragrep.net_01.channel.socket; import com.teragrep.buf_01.buffer.lease.TrackedLease; +import com.teragrep.buf_01.buffer.lease.TrackedMemorySegmentLease; import tlschannel.TlsChannel; import java.io.IOException; import java.lang.foreign.MemorySegment; +import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; +import java.util.ArrayList; import java.util.List; final class TLSSocket implements Socket { @@ -67,15 +70,101 @@ final class TLSSocket implements Socket { } @Override - public ReadResult read(List> dsts) throws IOException { - throw new UnsupportedOperationException(); - //return tlsChannel.read(dsts); + public ReadResult read(List> srcs) throws IOException { + final List> rv = new ArrayList<>(srcs.size()); + final List byteBuffers = new ArrayList<>(srcs.size()); + srcs.forEach(src -> { + byteBuffers.add(src.leasedObject().asByteBuffer()); + }); + + final long readBytes = tlsChannel.read(byteBuffers.toArray(new ByteBuffer[0])); + + long bytesLeft = readBytes; + boolean allRead = false; + for (final TrackedLease bufferLease : srcs) { + final long byteSize = bufferLease.leasedObject().byteSize(); + + if (!allRead && readBytes > 0) { + // same as ByteBuffer.flip() + final long diff = bytesLeft - byteSize; + if (diff < 0) { + // mem.segment bigger than bytes left. + // set limit to read amount. + final long limit = byteSize - Math.abs(diff); + rv.add(new TrackedMemorySegmentLease(bufferLease, 0L, limit)); + } + else { + //else: full mem.segment used, no need to set limit. + rv.add(new TrackedMemorySegmentLease(bufferLease)); + } + } + + bytesLeft -= byteSize; + + if (bytesLeft <= 0) { + allRead = true; + } + } + + //rv.forEach(l -> { + System.out.println("Lease:"); + /*for (long i = 0 ; i < l.leasedObject().byteSize(); i++) { + System.out.printf("%s", (char)l.leasedObject().get(ValueLayout.JAVA_BYTE, i)); + }*/ + + /* while (l.hasNext()) { + System.out.printf("%s", (char)l.next().byteValue()); + } + + System.out.println();*/ + //}); + return new ReadResult(readBytes, rv); } @Override - public WrittenResult write(List> dsts) throws IOException { - throw new UnsupportedOperationException(); - //return tlsChannel.write(dsts); + public WrittenResult write(List> leases) throws IOException { + final List buffersToWrite = new ArrayList<>(leases.size()); + final List> rv = new ArrayList<>(leases.size()); + + for (final TrackedLease lease : leases) { + buffersToWrite.add(lease.leasedObject().asByteBuffer()); + } + + final long bytesWritten = tlsChannel.write(buffersToWrite.toArray(new ByteBuffer[0])); + System.out.println("wrote bytes: " + bytesWritten); + + long bytesLeft = bytesWritten; + boolean allWritten = false; + for (final TrackedLease bufferLease : leases) { + final long byteSize = bufferLease.leasedObject().byteSize(); + + if (!allWritten && bytesWritten > 0) { + // same as ByteBuffer.flip() + final long diff = bytesLeft - byteSize; + if (diff < 0) { + // mem.segment bigger than bytes left. + // set limit to written amount. + final long limit = byteSize - Math.abs(diff); + //rv.add(new TrackedMemorySegmentLease(bufferLease, new AtomicLong(0L), new AtomicLong(limit))); + bufferLease.position(0L); + bufferLease.limit(limit); + rv.add(bufferLease); + } + else { + //else: full mem.segment used, no need to set limit. + //rv.add(new TrackedMemorySegmentLease(bufferLease)); + rv.add(bufferLease); + } + } + + bytesLeft -= byteSize; + + if (bytesLeft <= 0) { + allWritten = true; + } + } + + return new WrittenResult(bytesWritten, rv); } @Override From 97d542577ab479dea29fc13495c2f32d2a05fa34 Mon Sep 17 00:00:00 2001 From: eemhu <125959687+eemhu@users.noreply.github.com> Date: Tue, 21 Apr 2026 13:13:02 +0300 Subject: [PATCH 27/45] update buf_01 to 1.1.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index bcc8ad4..84c3b4b 100644 --- a/pom.xml +++ b/pom.xml @@ -38,7 +38,7 @@ UTF-8 0.0.1 - 1.0.0 + 1.1.0 3.0.0 From 111368c50104a5ed1ef4aa59d6d6ce4d876cef01 Mon Sep 17 00:00:00 2001 From: eemhu <125959687+eemhu@users.noreply.github.com> Date: Tue, 21 Apr 2026 13:49:19 +0300 Subject: [PATCH 28/45] remove unnecessary code --- .../channel/buffer/writable/WriteableAccess.java | 1 - .../buffer/writable/WriteableClosure.java | 1 - .../buffer/writable/WriteableLeaseful.java | 1 - .../channel/buffer/writable/Writeables.java | 1 - .../net_01/channel/socket/PlainSocket.java | 16 ---------------- .../teragrep/net_01/channel/socket/Socket.java | 1 - .../net_01/channel/socket/TLSSocket.java | 15 --------------- 7 files changed, 36 deletions(-) diff --git a/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableAccess.java b/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableAccess.java index 78cb506..4a49bf2 100644 --- a/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableAccess.java +++ b/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableAccess.java @@ -46,7 +46,6 @@ package com.teragrep.net_01.channel.buffer.writable; import com.teragrep.buf_01.buffer.lease.TrackedLease; -import com.teragrep.buf_01.buffer.lease.TrackedMemorySegmentLease; import com.teragrep.net_01.channel.buffer.access.Access; import com.teragrep.net_01.channel.buffer.access.Lease; diff --git a/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableClosure.java b/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableClosure.java index 22f4895..2b291d9 100644 --- a/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableClosure.java +++ b/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableClosure.java @@ -46,7 +46,6 @@ package com.teragrep.net_01.channel.buffer.writable; import com.teragrep.buf_01.buffer.lease.TrackedLease; -import com.teragrep.buf_01.buffer.lease.TrackedMemorySegmentLease; import com.teragrep.net_01.channel.context.EstablishedContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableLeaseful.java b/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableLeaseful.java index dd23d98..51688b9 100644 --- a/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableLeaseful.java +++ b/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableLeaseful.java @@ -47,7 +47,6 @@ import com.teragrep.buf_01.buffer.lease.OpenableLease; import com.teragrep.buf_01.buffer.lease.TrackedLease; -import com.teragrep.buf_01.buffer.lease.TrackedMemorySegmentLease; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/com/teragrep/net_01/channel/buffer/writable/Writeables.java b/src/main/java/com/teragrep/net_01/channel/buffer/writable/Writeables.java index fdb46c4..c9a1bb2 100644 --- a/src/main/java/com/teragrep/net_01/channel/buffer/writable/Writeables.java +++ b/src/main/java/com/teragrep/net_01/channel/buffer/writable/Writeables.java @@ -46,7 +46,6 @@ package com.teragrep.net_01.channel.buffer.writable; import com.teragrep.buf_01.buffer.lease.TrackedLease; -import com.teragrep.buf_01.buffer.lease.TrackedMemorySegmentLease; import java.lang.foreign.MemorySegment; import java.util.ArrayList; diff --git a/src/main/java/com/teragrep/net_01/channel/socket/PlainSocket.java b/src/main/java/com/teragrep/net_01/channel/socket/PlainSocket.java index f902317..98d9972 100644 --- a/src/main/java/com/teragrep/net_01/channel/socket/PlainSocket.java +++ b/src/main/java/com/teragrep/net_01/channel/socket/PlainSocket.java @@ -54,7 +54,6 @@ import java.nio.channels.SocketChannel; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.atomic.AtomicLong; final class PlainSocket implements Socket { @@ -104,18 +103,6 @@ public ReadResult read(List> srcs) throws IOExceptio } } - //rv.forEach(l -> { - System.out.println("Lease:"); - /*for (long i = 0 ; i < l.leasedObject().byteSize(); i++) { - System.out.printf("%s", (char)l.leasedObject().get(ValueLayout.JAVA_BYTE, i)); - }*/ - - /* while (l.hasNext()) { - System.out.printf("%s", (char)l.next().byteValue()); - } - - System.out.println();*/ - //}); return new ReadResult(readBytes, rv); } @@ -129,7 +116,6 @@ public WrittenResult write(List> leases) throws IOEx } final long bytesWritten = socketChannel.write(buffersToWrite.toArray(new ByteBuffer[0])); - System.out.println("wrote bytes: " + bytesWritten); long bytesLeft = bytesWritten; boolean allWritten = false; @@ -143,14 +129,12 @@ public WrittenResult write(List> leases) throws IOEx // mem.segment bigger than bytes left. // set limit to written amount. final long limit = byteSize - Math.abs(diff); - //rv.add(new TrackedMemorySegmentLease(bufferLease, new AtomicLong(0L), new AtomicLong(limit))); bufferLease.position(0L); bufferLease.limit(limit); rv.add(bufferLease); } else { //else: full mem.segment used, no need to set limit. - //rv.add(new TrackedMemorySegmentLease(bufferLease)); rv.add(bufferLease); } } diff --git a/src/main/java/com/teragrep/net_01/channel/socket/Socket.java b/src/main/java/com/teragrep/net_01/channel/socket/Socket.java index 8faebe8..75be296 100644 --- a/src/main/java/com/teragrep/net_01/channel/socket/Socket.java +++ b/src/main/java/com/teragrep/net_01/channel/socket/Socket.java @@ -49,7 +49,6 @@ import java.io.IOException; import java.lang.foreign.MemorySegment; -import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; import java.util.List; diff --git a/src/main/java/com/teragrep/net_01/channel/socket/TLSSocket.java b/src/main/java/com/teragrep/net_01/channel/socket/TLSSocket.java index 31d7b15..72e6040 100644 --- a/src/main/java/com/teragrep/net_01/channel/socket/TLSSocket.java +++ b/src/main/java/com/teragrep/net_01/channel/socket/TLSSocket.java @@ -106,18 +106,6 @@ public ReadResult read(List> srcs) throws IOExceptio } } - //rv.forEach(l -> { - System.out.println("Lease:"); - /*for (long i = 0 ; i < l.leasedObject().byteSize(); i++) { - System.out.printf("%s", (char)l.leasedObject().get(ValueLayout.JAVA_BYTE, i)); - }*/ - - /* while (l.hasNext()) { - System.out.printf("%s", (char)l.next().byteValue()); - } - - System.out.println();*/ - //}); return new ReadResult(readBytes, rv); } @@ -131,7 +119,6 @@ public WrittenResult write(List> leases) throws IOEx } final long bytesWritten = tlsChannel.write(buffersToWrite.toArray(new ByteBuffer[0])); - System.out.println("wrote bytes: " + bytesWritten); long bytesLeft = bytesWritten; boolean allWritten = false; @@ -145,14 +132,12 @@ public WrittenResult write(List> leases) throws IOEx // mem.segment bigger than bytes left. // set limit to written amount. final long limit = byteSize - Math.abs(diff); - //rv.add(new TrackedMemorySegmentLease(bufferLease, new AtomicLong(0L), new AtomicLong(limit))); bufferLease.position(0L); bufferLease.limit(limit); rv.add(bufferLease); } else { //else: full mem.segment used, no need to set limit. - //rv.add(new TrackedMemorySegmentLease(bufferLease)); rv.add(bufferLease); } } From 8ce1638eaec59210e7a4b0778ec19e8fd63a9c72 Mon Sep 17 00:00:00 2001 From: eemhu <125959687+eemhu@users.noreply.github.com> Date: Tue, 21 Apr 2026 14:44:34 +0300 Subject: [PATCH 29/45] remove TrackedMemorySegmentLeaseTest --- .../buffer/TrackedMemorySegmentLeaseTest.java | 84 ------------------- 1 file changed, 84 deletions(-) delete mode 100644 src/test/java/com/teragrep/net_01/channel/context/buffer/TrackedMemorySegmentLeaseTest.java diff --git a/src/test/java/com/teragrep/net_01/channel/context/buffer/TrackedMemorySegmentLeaseTest.java b/src/test/java/com/teragrep/net_01/channel/context/buffer/TrackedMemorySegmentLeaseTest.java deleted file mode 100644 index a96a453..0000000 --- a/src/test/java/com/teragrep/net_01/channel/context/buffer/TrackedMemorySegmentLeaseTest.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Java Zero Copy Networking Library net_01 - * Copyright (C) 2024 Suomen Kanuuna Oy - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - * - * Additional permission under GNU Affero General Public License version 3 - * section 7 - * - * If you modify this Program, or any covered work, by linking or combining it - * with other code, such other code is not for that reason alone subject to any - * of the requirements of the GNU Affero GPL version 3 as long as this Program - * is the same Program as licensed from Suomen Kanuuna Oy without any additional - * modifications. - * - * Supplemented terms under GNU Affero General Public License version 3 - * section 7 - * - * Origin of the software must be attributed to Suomen Kanuuna Oy. Any modified - * versions must be marked as "Modified version of" The Program. - * - * Names of the licensors and authors may not be used for publicity purposes. - * - * No rights are granted for use of trade names, trademarks, or service marks - * which are in The Program if any. - * - * Licensee must indemnify licensors and authors for any liability that these - * contractual assumptions impose on licensors and authors. - * - * To the extent this program is licensed as part of the Commercial versions of - * Teragrep, the applicable Commercial License may apply to this file if you as - * a licensee so wish it. - */ -package com.teragrep.net_01.channel.context.buffer; - -import com.teragrep.buf_01.buffer.lease.MemorySegmentLeaseStub; -import com.teragrep.buf_01.buffer.lease.TrackedLease; -import com.teragrep.buf_01.buffer.lease.TrackedMemorySegmentLease; -import com.teragrep.buf_01.buffer.pool.OpeningPool; -import com.teragrep.buf_01.buffer.supply.ArenaMemorySegmentLeaseSupplier; -import com.teragrep.poj_01.pool.UnboundPool; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -import java.lang.foreign.Arena; -import java.lang.foreign.MemorySegment; - -public final class TrackedMemorySegmentLeaseTest { - - @Test - void testProgressing() { - final OpeningPool pool = new OpeningPool( - new UnboundPool<>(new ArenaMemorySegmentLeaseSupplier(Arena.ofShared(), 5), new MemorySegmentLeaseStub()) - ); - final TrackedLease trackedLease = new TrackedMemorySegmentLease(pool.get()); - - Assertions.assertEquals(0L, trackedLease.currentPosition()); - - int loops = 0; - for (int i = 0; i < 5; i++) { - Assertions.assertEquals(i, trackedLease.currentPosition()); - Assertions.assertTrue(trackedLease.hasNext()); - Assertions.assertEquals((byte) 0, trackedLease.next()); - loops++; - } - Assertions.assertEquals(5, loops); - - Assertions.assertFalse(trackedLease.hasNext()); - Assertions.assertThrows(IndexOutOfBoundsException.class, trackedLease::next); - Assertions.assertEquals(5L, trackedLease.currentPosition()); - } -} From d6db32bc9d830a383fe87cec0ac45591d58f2c55 Mon Sep 17 00:00:00 2001 From: eemhu <125959687+eemhu@users.noreply.github.com> Date: Tue, 21 Apr 2026 14:46:06 +0300 Subject: [PATCH 30/45] remove all printlns --- .../com/teragrep/net_01/channel/context/IngressImpl.java | 4 ---- .../com/teragrep/net_01/channel/context/ListenContext.java | 1 - src/main/java/com/teragrep/net_01/eventloop/EventLoop.java | 1 - .../com/teragrep/net_01/channel/socket/SocketTest.java | 7 ------- 4 files changed, 13 deletions(-) diff --git a/src/main/java/com/teragrep/net_01/channel/context/IngressImpl.java b/src/main/java/com/teragrep/net_01/channel/context/IngressImpl.java index 159fd12..fdb51db 100644 --- a/src/main/java/com/teragrep/net_01/channel/context/IngressImpl.java +++ b/src/main/java/com/teragrep/net_01/channel/context/IngressImpl.java @@ -108,12 +108,10 @@ public void run() { long readBytes = readData(); if (!isDataAvailable(readBytes)) { - System.out.println("No data available"); break; } boolean continueReading = true; - System.out.println("activeBuffers.isEmpty=" + activeBuffers.isEmpty()); while (!activeBuffers.isEmpty()) { // IMPORTANT: current tls implementation will skip bytes if BufferLeases are not fully consumed. TrackedLease bufferLease = activeBuffers.removeFirst(); @@ -137,7 +135,6 @@ public void run() { if (bufferLease.hasNext()) { // return back as it has some remaining - System.out.println("something remaining"); LOGGER.debug("pushBack bufferLease id <{}>", bufferLease.id()); activeBuffers.add(bufferLease); if (LOGGER.isDebugEnabled()) { @@ -246,7 +243,6 @@ private long readData() throws IOException { final ReadResult result = establishedContext.socket().read(trackedMemorySegmentLeases); activeBuffers.addAll(result.leases()); - System.out.println("buffers.size=" + activeBuffers.size()); LOGGER.debug("establishedContext.read got <{}> bytes from socket", result.bytes()); diff --git a/src/main/java/com/teragrep/net_01/channel/context/ListenContext.java b/src/main/java/com/teragrep/net_01/channel/context/ListenContext.java index 6a018cb..50c020e 100644 --- a/src/main/java/com/teragrep/net_01/channel/context/ListenContext.java +++ b/src/main/java/com/teragrep/net_01/channel/context/ListenContext.java @@ -85,7 +85,6 @@ public final class ListenContext implements Context { @Override public void handleEvent(SelectionKey selectionKey) { - System.out.println("handling event: " + selectionKey); try { if (selectionKey.isAcceptable()) { // create the client socket for a newly received connection diff --git a/src/main/java/com/teragrep/net_01/eventloop/EventLoop.java b/src/main/java/com/teragrep/net_01/eventloop/EventLoop.java index 1f58e6b..b4678c8 100644 --- a/src/main/java/com/teragrep/net_01/eventloop/EventLoop.java +++ b/src/main/java/com/teragrep/net_01/eventloop/EventLoop.java @@ -197,7 +197,6 @@ public void run() { try { LOGGER.info("Started"); while (!stop.get()) { - System.out.println("polling " + Thread.currentThread().getName()); poll(); } } diff --git a/src/test/java/com/teragrep/net_01/channel/socket/SocketTest.java b/src/test/java/com/teragrep/net_01/channel/socket/SocketTest.java index 5a68682..761d4dc 100644 --- a/src/test/java/com/teragrep/net_01/channel/socket/SocketTest.java +++ b/src/test/java/com/teragrep/net_01/channel/socket/SocketTest.java @@ -65,7 +65,6 @@ import java.nio.channels.ServerSocketChannel; import java.nio.charset.StandardCharsets; import java.util.ArrayList; -import java.util.Arrays; import java.util.Iterator; import java.util.List; @@ -179,7 +178,6 @@ private List> stringToBuffer(final String str) { int currentIndex = 0; long size = currentLease.leasedObject().byteSize(); for (int i = 0; i < bytes.length; i++) { - System.out.println("i: " + i + " " + bytes[i]); if (currentIndex < size) { currentLease.leasedObject().set(ValueLayout.JAVA_BYTE, currentIndex, bytes[i]); currentIndex++; @@ -195,11 +193,6 @@ private List> stringToBuffer(final String str) { } } - System.out.println("stringToBuffer"); - leases.forEach(l -> { - System.out.println(Arrays.toString(l.leasedObject().toArray(ValueLayout.JAVA_BYTE))); - }); - return leases; } From 1f808bc8dfa7c619c1fa21ee711de4d55ccc2433 Mon Sep 17 00:00:00 2001 From: eemhu <125959687+eemhu@users.noreply.github.com> Date: Thu, 23 Apr 2026 17:06:52 +0300 Subject: [PATCH 31/45] interrupt eventThread in AfterAll in ServerTests. fixes port in use error --- .../channel/server/ServerReceivingTest.java | 4 +- .../channel/server/ServerSendingTest.java | 37 ++++++++++--------- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/src/test/java/com/teragrep/net_01/channel/server/ServerReceivingTest.java b/src/test/java/com/teragrep/net_01/channel/server/ServerReceivingTest.java index 4c2aa3a..93d4cc8 100644 --- a/src/test/java/com/teragrep/net_01/channel/server/ServerReceivingTest.java +++ b/src/test/java/com/teragrep/net_01/channel/server/ServerReceivingTest.java @@ -69,6 +69,7 @@ public final class ServerReceivingTest { private Server server; private CountDownLatch countDownLatch; private final List> messages = new ArrayList<>(); + private Thread elT; @BeforeAll void beforeAll() { @@ -82,7 +83,7 @@ void beforeAll() { final EventLoop el = Assertions.assertDoesNotThrow(eventLoopFactory::create); // eventLoopThread must run, otherwise nothing will be processed - final Thread elT = new Thread(el); + elT = new Thread(el); elT.start(); final ServerFactory serverFactory = new ServerFactory( @@ -98,6 +99,7 @@ void beforeAll() { @AfterAll void afterAll() { Assertions.assertDoesNotThrow(this.server::close); + elT.interrupt(); } @AfterEach diff --git a/src/test/java/com/teragrep/net_01/channel/server/ServerSendingTest.java b/src/test/java/com/teragrep/net_01/channel/server/ServerSendingTest.java index e0e6466..f31157f 100644 --- a/src/test/java/com/teragrep/net_01/channel/server/ServerSendingTest.java +++ b/src/test/java/com/teragrep/net_01/channel/server/ServerSendingTest.java @@ -72,6 +72,7 @@ public final class ServerSendingTest { private Server server; private CountDownLatch countDownLatch; private OpeningPool pool; + private Thread elT; @BeforeAll void beforeAll() { @@ -85,7 +86,7 @@ void beforeAll() { final EventLoop el = Assertions.assertDoesNotThrow(eventLoopFactory::create); // eventLoopThread must run, otherwise nothing will be processed - final Thread elT = new Thread(el); + elT = new Thread(el); elT.start(); final ServerFactory serverFactory = new ServerFactory( @@ -102,30 +103,30 @@ void beforeAll() { void afterAll() { Assertions.assertDoesNotThrow(this.server::close); Assertions.assertDoesNotThrow(this.pool::close); + elT.interrupt(); } @Test void testSending() { - this.countDownLatch = new CountDownLatch(1); - final java.net.Socket clientSocket = Assertions - .assertDoesNotThrow(() -> new java.net.Socket("localhost", 9090)); + Assertions.assertDoesNotThrow(() -> { + this.countDownLatch = new CountDownLatch(1); + try (final java.net.Socket clientSocket = new java.net.Socket("localhost", 9090)) { + final PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true); + final BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); + final String request = "Hello world! This is some input"; + out.println(request); + out.flush(); - final PrintWriter out = new PrintWriter(Assertions.assertDoesNotThrow(clientSocket::getOutputStream), true); - final BufferedReader in = new BufferedReader( - new InputStreamReader(Assertions.assertDoesNotThrow(clientSocket::getInputStream)) - ); - final String request = "Hello world! This is some input"; - out.println(request); - out.flush(); + countDownLatch.await(); - Assertions.assertDoesNotThrow(() -> countDownLatch.await()); + final String resp = Assertions.assertDoesNotThrow(in::readLine); - final String resp = Assertions.assertDoesNotThrow(in::readLine); + // SendingClock replies with the request + Assertions.assertEquals(request, resp); + in.close(); + out.close(); + } + }); - // SendingClock replies with the request - Assertions.assertEquals(request, resp); - Assertions.assertDoesNotThrow(in::close); - Assertions.assertDoesNotThrow(out::close); - Assertions.assertDoesNotThrow(clientSocket::close); } } From 9973fe0668674157637e51e165c5e12034c63c22 Mon Sep 17 00:00:00 2001 From: eemhu <125959687+eemhu@users.noreply.github.com> Date: Thu, 23 Apr 2026 17:07:03 +0300 Subject: [PATCH 32/45] update jacoco maven plugin to 0.8.14 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 84c3b4b..98f1b89 100644 --- a/pom.xml +++ b/pom.xml @@ -130,7 +130,7 @@ org.jacoco jacoco-maven-plugin - 0.8.12 + 0.8.14 From ca7edf0ecd7c458cf0328e23cc4fca6450a6a746 Mon Sep 17 00:00:00 2001 From: eemhu <125959687+eemhu@users.noreply.github.com> Date: Fri, 24 Apr 2026 15:25:07 +0300 Subject: [PATCH 33/45] replace some of the lists in Socket objects with arrays. --- .../net_01/channel/socket/PlainSocket.java | 24 ++++++++++--------- .../net_01/channel/socket/TLSSocket.java | 24 ++++++++++--------- 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/src/main/java/com/teragrep/net_01/channel/socket/PlainSocket.java b/src/main/java/com/teragrep/net_01/channel/socket/PlainSocket.java index 98d9972..8abcd58 100644 --- a/src/main/java/com/teragrep/net_01/channel/socket/PlainSocket.java +++ b/src/main/java/com/teragrep/net_01/channel/socket/PlainSocket.java @@ -68,13 +68,14 @@ final class PlainSocket implements Socket { @Override public ReadResult read(List> srcs) throws IOException { - final List> rv = new ArrayList<>(srcs.size()); - final List byteBuffers = new ArrayList<>(srcs.size()); - srcs.forEach(src -> { - byteBuffers.add(src.leasedObject().asByteBuffer()); - }); + final int size = srcs.size(); + final List> rv = new ArrayList<>(size); + final ByteBuffer[] byteBuffers = new ByteBuffer[size]; + for (int i = 0; i < size; i++) { + byteBuffers[i] = srcs.get(i).leasedObject().asByteBuffer(); + } - final long readBytes = socketChannel.read(byteBuffers.toArray(new ByteBuffer[0])); + final long readBytes = socketChannel.read(byteBuffers); long bytesLeft = readBytes; boolean allRead = false; @@ -108,14 +109,15 @@ public ReadResult read(List> srcs) throws IOExceptio @Override public WrittenResult write(List> leases) throws IOException { - final List buffersToWrite = new ArrayList<>(leases.size()); - final List> rv = new ArrayList<>(leases.size()); + final int size = leases.size(); + final ByteBuffer[] buffersToWrite = new ByteBuffer[size]; + final List> rv = new ArrayList<>(size); - for (final TrackedLease lease : leases) { - buffersToWrite.add(lease.leasedObject().asByteBuffer()); + for (int i = 0; i < size; i++) { + buffersToWrite[i] = leases.get(i).leasedObject().asByteBuffer(); } - final long bytesWritten = socketChannel.write(buffersToWrite.toArray(new ByteBuffer[0])); + final long bytesWritten = socketChannel.write(buffersToWrite); long bytesLeft = bytesWritten; boolean allWritten = false; diff --git a/src/main/java/com/teragrep/net_01/channel/socket/TLSSocket.java b/src/main/java/com/teragrep/net_01/channel/socket/TLSSocket.java index 72e6040..b5440bc 100644 --- a/src/main/java/com/teragrep/net_01/channel/socket/TLSSocket.java +++ b/src/main/java/com/teragrep/net_01/channel/socket/TLSSocket.java @@ -71,13 +71,14 @@ final class TLSSocket implements Socket { @Override public ReadResult read(List> srcs) throws IOException { - final List> rv = new ArrayList<>(srcs.size()); - final List byteBuffers = new ArrayList<>(srcs.size()); - srcs.forEach(src -> { - byteBuffers.add(src.leasedObject().asByteBuffer()); - }); + final int size = srcs.size(); + final List> rv = new ArrayList<>(size); + final ByteBuffer[] byteBuffers = new ByteBuffer[size]; + for (int i = 0; i < size; i++) { + byteBuffers[i] = srcs.get(i).leasedObject().asByteBuffer(); + } - final long readBytes = tlsChannel.read(byteBuffers.toArray(new ByteBuffer[0])); + final long readBytes = tlsChannel.read(byteBuffers); long bytesLeft = readBytes; boolean allRead = false; @@ -111,14 +112,15 @@ public ReadResult read(List> srcs) throws IOExceptio @Override public WrittenResult write(List> leases) throws IOException { - final List buffersToWrite = new ArrayList<>(leases.size()); - final List> rv = new ArrayList<>(leases.size()); + final int size = leases.size(); + final ByteBuffer[] buffersToWrite = new ByteBuffer[size]; + final List> rv = new ArrayList<>(size); - for (final TrackedLease lease : leases) { - buffersToWrite.add(lease.leasedObject().asByteBuffer()); + for (int i = 0; i < size; i++) { + buffersToWrite[i] = leases.get(i).leasedObject().asByteBuffer(); } - final long bytesWritten = tlsChannel.write(buffersToWrite.toArray(new ByteBuffer[0])); + final long bytesWritten = tlsChannel.write(buffersToWrite); long bytesLeft = bytesWritten; boolean allWritten = false; From 53ce94aa87c879b3d59211b0ee24586b74799622 Mon Sep 17 00:00:00 2001 From: eemhu <125959687+eemhu@users.noreply.github.com> Date: Tue, 28 Apr 2026 09:45:38 +0300 Subject: [PATCH 34/45] cleanup duplicate code, add toLeases method to StringToLease test object --- .../net_01/channel/StringToLease.java | 6 +++- .../net_01/channel/socket/SocketTest.java | 35 ++----------------- 2 files changed, 8 insertions(+), 33 deletions(-) diff --git a/src/test/java/com/teragrep/net_01/channel/StringToLease.java b/src/test/java/com/teragrep/net_01/channel/StringToLease.java index ad4f272..94da068 100644 --- a/src/test/java/com/teragrep/net_01/channel/StringToLease.java +++ b/src/test/java/com/teragrep/net_01/channel/StringToLease.java @@ -69,6 +69,10 @@ public StringToLease(final String origin, OpeningPool pool) { } public Writeable toWriteable() { + return new StringWriteable(toLeases()); + } + + public List> toLeases() { final byte[] bytes = origin.getBytes(StandardCharsets.UTF_8); final List> leases = new LeaseMultiGet(pool).get(bytes.length); final List> trackedLeases = new ArrayList<>(leases.size()); @@ -84,6 +88,6 @@ public Writeable toWriteable() { } } - return new StringWriteable(trackedLeases); + return trackedLeases; } } diff --git a/src/test/java/com/teragrep/net_01/channel/socket/SocketTest.java b/src/test/java/com/teragrep/net_01/channel/socket/SocketTest.java index 761d4dc..3296989 100644 --- a/src/test/java/com/teragrep/net_01/channel/socket/SocketTest.java +++ b/src/test/java/com/teragrep/net_01/channel/socket/SocketTest.java @@ -52,6 +52,7 @@ import com.teragrep.buf_01.buffer.pool.LeaseMultiGet; import com.teragrep.buf_01.buffer.pool.OpeningPool; import com.teragrep.buf_01.buffer.supply.ArenaMemorySegmentLeaseSupplier; +import com.teragrep.net_01.channel.StringToLease; import com.teragrep.poj_01.pool.UnboundPool; import org.junit.jupiter.api.*; @@ -60,12 +61,9 @@ import java.io.PrintWriter; import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; -import java.lang.foreign.ValueLayout; import java.net.InetSocketAddress; import java.nio.channels.ServerSocketChannel; -import java.nio.charset.StandardCharsets; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; @TestInstance(TestInstance.Lifecycle.PER_CLASS) @@ -120,7 +118,7 @@ void testPlainSocketWrite() { // Init PlainSocket final Socket socket = new PlainSocket(socketCh.accept()); - socket.write(stringToBuffer("helloWorld\n")); + socket.write(new StringToLease("helloWorld\n", pool).toLeases()); final String readLine = in.readLine(); @@ -169,34 +167,7 @@ private String bufferToString(final List> leases) { return stringBuilder.toString(); } - private List> stringToBuffer(final String str) { - final byte[] bytes = str.getBytes(StandardCharsets.UTF_8); - final List> leases = emptyBuffers(bytes.length); - - Iterator> it = leases.iterator(); - TrackedLease currentLease = it.next(); - int currentIndex = 0; - long size = currentLease.leasedObject().byteSize(); - for (int i = 0; i < bytes.length; i++) { - if (currentIndex < size) { - currentLease.leasedObject().set(ValueLayout.JAVA_BYTE, currentIndex, bytes[i]); - currentIndex++; - } - else { - if (!it.hasNext()) { - throw new IllegalStateException(); - } - currentLease = it.next(); - currentIndex = 0; - size = currentLease.leasedObject().byteSize(); - currentLease.leasedObject().set(ValueLayout.JAVA_BYTE, currentIndex, bytes[i]); - } - } - - return leases; - } - - private List> emptyBuffers(int bytes) { + private List> emptyBuffers(final int bytes) { final List> leases = new LeaseMultiGet(pool).get(bytes); final List> rv = new ArrayList<>(leases.size()); From eb5cfe87b30d15e4706d04711edd032bee6032e4 Mon Sep 17 00:00:00 2001 From: eemhu <125959687+eemhu@users.noreply.github.com> Date: Tue, 28 Apr 2026 13:10:05 +0300 Subject: [PATCH 35/45] WriteableInvalidation also sets limit and position to 0. --- .../channel/buffer/writable/WriteableInvalidation.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableInvalidation.java b/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableInvalidation.java index ec9c4b7..3f6c16d 100644 --- a/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableInvalidation.java +++ b/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableInvalidation.java @@ -48,13 +48,11 @@ import com.teragrep.buf_01.buffer.lease.TrackedLease; import java.lang.foreign.MemorySegment; -import java.nio.ByteBuffer; import java.util.List; /** - * Decoration of {@link Writeable} Invalidates a writable so that {@link ByteBuffer}s returned from - * {@link Writeable#memorySegmentLeases()} have position and limit set to zero. Because ByteBuffer can not be Decorated - * directly this is only viable alternative to best-effort invalidate access to it. + * Decoration of {@link Writeable} Invalidates a writable so TrackedLeases' position and limit is set to zero and the + * lease is also closed, which should fill the underlying MemorySegment with zeroes. */ public final class WriteableInvalidation implements Writeable { @@ -68,6 +66,8 @@ public WriteableInvalidation(Writeable writeable) { public void close() { for (final TrackedLease lease : memorySegmentLeases()) { try { + lease.position(0L); + lease.limit(0L); lease.close(); } catch (final Exception e) { From ea96ece4ee1dc8ab78639cd75f0184d67553ac21 Mon Sep 17 00:00:00 2001 From: eemhu <125959687+eemhu@users.noreply.github.com> Date: Tue, 28 Apr 2026 15:29:51 +0300 Subject: [PATCH 36/45] writeableTest --- .../buffer/writable/WriteableTest.java | 97 +++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 src/test/java/com/teragrep/net_01/channel/buffer/writable/WriteableTest.java diff --git a/src/test/java/com/teragrep/net_01/channel/buffer/writable/WriteableTest.java b/src/test/java/com/teragrep/net_01/channel/buffer/writable/WriteableTest.java new file mode 100644 index 0000000..6da7730 --- /dev/null +++ b/src/test/java/com/teragrep/net_01/channel/buffer/writable/WriteableTest.java @@ -0,0 +1,97 @@ +/* + * Java Zero Copy Networking Library net_01 + * Copyright (C) 2024 Suomen Kanuuna Oy + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * + * Additional permission under GNU Affero General Public License version 3 + * section 7 + * + * If you modify this Program, or any covered work, by linking or combining it + * with other code, such other code is not for that reason alone subject to any + * of the requirements of the GNU Affero GPL version 3 as long as this Program + * is the same Program as licensed from Suomen Kanuuna Oy without any additional + * modifications. + * + * Supplemented terms under GNU Affero General Public License version 3 + * section 7 + * + * Origin of the software must be attributed to Suomen Kanuuna Oy. Any modified + * versions must be marked as "Modified version of" The Program. + * + * Names of the licensors and authors may not be used for publicity purposes. + * + * No rights are granted for use of trade names, trademarks, or service marks + * which are in The Program if any. + * + * Licensee must indemnify licensors and authors for any liability that these + * contractual assumptions impose on licensors and authors. + * + * To the extent this program is licensed as part of the Commercial versions of + * Teragrep, the applicable Commercial License may apply to this file if you as + * a licensee so wish it. + */ +package com.teragrep.net_01.channel.buffer.writable; + +import com.teragrep.buf_01.buffer.lease.MemorySegmentLeaseStub; +import com.teragrep.buf_01.buffer.lease.OpenableLease; +import com.teragrep.buf_01.buffer.lease.TrackedLease; +import com.teragrep.buf_01.buffer.lease.TrackedMemorySegmentLease; +import com.teragrep.buf_01.buffer.pool.LeaseMultiGet; +import com.teragrep.buf_01.buffer.pool.OpeningPool; +import com.teragrep.buf_01.buffer.supply.ArenaMemorySegmentLeaseSupplier; +import com.teragrep.net_01.channel.context.StringWriteable; +import com.teragrep.poj_01.pool.UnboundPool; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; +import java.util.ArrayList; +import java.util.List; + +public final class WriteableTest { + + @Test + void testWriteableHasRemaining() { + final OpeningPool pool = new OpeningPool( + new UnboundPool<>(new ArenaMemorySegmentLeaseSupplier(Arena.ofShared(), 128), new MemorySegmentLeaseStub()) + ); + + final List> leases = new LeaseMultiGet(pool).get(32L); + final List> trackedLeases = new ArrayList<>(leases.size()); + + for (final OpenableLease lease : leases) { + trackedLeases.add(new TrackedMemorySegmentLease(lease)); + } + + final Writeable w = new StringWriteable(trackedLeases); + + Assertions.assertEquals(trackedLeases, w.memorySegmentLeases()); + Assertions.assertEquals(1, w.memorySegmentLeases().size()); + final TrackedLease lease = trackedLeases.getFirst(); + + int i; + for (i = 0; i < 128; i++) { + Assertions.assertTrue(w.hasRemaining()); + Assertions.assertTrue(lease.hasNext()); + lease.next(); + } + + Assertions.assertEquals(128, i); + Assertions.assertFalse(w.hasRemaining()); + Assertions.assertFalse(lease.hasNext()); + } +} From 1c087e0c025eebdf3ea007e2a3cc8969c91a22b8 Mon Sep 17 00:00:00 2001 From: eemhu <125959687+eemhu@users.noreply.github.com> Date: Tue, 28 Apr 2026 15:31:24 +0300 Subject: [PATCH 37/45] writeableTest with limit --- .../buffer/writable/WriteableTest.java | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/test/java/com/teragrep/net_01/channel/buffer/writable/WriteableTest.java b/src/test/java/com/teragrep/net_01/channel/buffer/writable/WriteableTest.java index 6da7730..b093085 100644 --- a/src/test/java/com/teragrep/net_01/channel/buffer/writable/WriteableTest.java +++ b/src/test/java/com/teragrep/net_01/channel/buffer/writable/WriteableTest.java @@ -94,4 +94,38 @@ void testWriteableHasRemaining() { Assertions.assertFalse(w.hasRemaining()); Assertions.assertFalse(lease.hasNext()); } + + @Test + void testWriteableHasRemainingWithSetLimit() { + final OpeningPool pool = new OpeningPool( + new UnboundPool<>(new ArenaMemorySegmentLeaseSupplier(Arena.ofShared(), 128), new MemorySegmentLeaseStub()) + ); + + final List> leases = new LeaseMultiGet(pool).get(32L); + final List> trackedLeases = new ArrayList<>(leases.size()); + + for (final OpenableLease lease : leases) { + trackedLeases.add(new TrackedMemorySegmentLease(lease)); + } + + final Writeable w = new StringWriteable(trackedLeases); + + Assertions.assertEquals(trackedLeases, w.memorySegmentLeases()); + Assertions.assertEquals(1, w.memorySegmentLeases().size()); + final TrackedLease lease = trackedLeases.getFirst(); + lease.limit(32L); + + int i; + for (i = 0; i < 32; i++) { + Assertions.assertTrue(w.hasRemaining()); + Assertions.assertTrue(lease.hasNext()); + lease.next(); + } + + Assertions.assertEquals(32, i); + Assertions.assertFalse(w.hasRemaining()); + Assertions.assertFalse(lease.hasNext()); + + Assertions.assertThrows(IndexOutOfBoundsException.class, lease::next); + } } From 185c28e02a5f77000c291acfcacb3abe57bf1e6b Mon Sep 17 00:00:00 2001 From: eemhu <125959687+eemhu@users.noreply.github.com> Date: Tue, 28 Apr 2026 15:32:17 +0300 Subject: [PATCH 38/45] writeableTest add assert --- .../teragrep/net_01/channel/buffer/writable/WriteableTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/java/com/teragrep/net_01/channel/buffer/writable/WriteableTest.java b/src/test/java/com/teragrep/net_01/channel/buffer/writable/WriteableTest.java index b093085..4e0b324 100644 --- a/src/test/java/com/teragrep/net_01/channel/buffer/writable/WriteableTest.java +++ b/src/test/java/com/teragrep/net_01/channel/buffer/writable/WriteableTest.java @@ -93,6 +93,8 @@ void testWriteableHasRemaining() { Assertions.assertEquals(128, i); Assertions.assertFalse(w.hasRemaining()); Assertions.assertFalse(lease.hasNext()); + + Assertions.assertThrows(IndexOutOfBoundsException.class, lease::next); } @Test From 7a26e197efcec411d48485fd9fae95d9cc08c4c5 Mon Sep 17 00:00:00 2001 From: eemhu <125959687+eemhu@users.noreply.github.com> Date: Tue, 28 Apr 2026 15:39:54 +0300 Subject: [PATCH 39/45] writeableTest add try-with-resources --- .../buffer/writable/WriteableTest.java | 66 +++++++++---------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/src/test/java/com/teragrep/net_01/channel/buffer/writable/WriteableTest.java b/src/test/java/com/teragrep/net_01/channel/buffer/writable/WriteableTest.java index 4e0b324..14bab07 100644 --- a/src/test/java/com/teragrep/net_01/channel/buffer/writable/WriteableTest.java +++ b/src/test/java/com/teragrep/net_01/channel/buffer/writable/WriteableTest.java @@ -77,24 +77,24 @@ void testWriteableHasRemaining() { trackedLeases.add(new TrackedMemorySegmentLease(lease)); } - final Writeable w = new StringWriteable(trackedLeases); - - Assertions.assertEquals(trackedLeases, w.memorySegmentLeases()); - Assertions.assertEquals(1, w.memorySegmentLeases().size()); - final TrackedLease lease = trackedLeases.getFirst(); - - int i; - for (i = 0; i < 128; i++) { - Assertions.assertTrue(w.hasRemaining()); - Assertions.assertTrue(lease.hasNext()); - lease.next(); + try (final Writeable w = new StringWriteable(trackedLeases)) { + Assertions.assertEquals(trackedLeases, w.memorySegmentLeases()); + Assertions.assertEquals(1, w.memorySegmentLeases().size()); + final TrackedLease lease = trackedLeases.getFirst(); + + int i; + for (i = 0; i < 128; i++) { + Assertions.assertTrue(w.hasRemaining()); + Assertions.assertTrue(lease.hasNext()); + lease.next(); + } + + Assertions.assertEquals(128, i); + Assertions.assertFalse(w.hasRemaining()); + Assertions.assertFalse(lease.hasNext()); + + Assertions.assertThrows(IndexOutOfBoundsException.class, lease::next); } - - Assertions.assertEquals(128, i); - Assertions.assertFalse(w.hasRemaining()); - Assertions.assertFalse(lease.hasNext()); - - Assertions.assertThrows(IndexOutOfBoundsException.class, lease::next); } @Test @@ -110,24 +110,24 @@ void testWriteableHasRemainingWithSetLimit() { trackedLeases.add(new TrackedMemorySegmentLease(lease)); } - final Writeable w = new StringWriteable(trackedLeases); + try (final Writeable w = new StringWriteable(trackedLeases)) { + Assertions.assertEquals(trackedLeases, w.memorySegmentLeases()); + Assertions.assertEquals(1, w.memorySegmentLeases().size()); + final TrackedLease lease = trackedLeases.getFirst(); + lease.limit(32L); - Assertions.assertEquals(trackedLeases, w.memorySegmentLeases()); - Assertions.assertEquals(1, w.memorySegmentLeases().size()); - final TrackedLease lease = trackedLeases.getFirst(); - lease.limit(32L); + int i; + for (i = 0; i < 32; i++) { + Assertions.assertTrue(w.hasRemaining()); + Assertions.assertTrue(lease.hasNext()); + lease.next(); + } - int i; - for (i = 0; i < 32; i++) { - Assertions.assertTrue(w.hasRemaining()); - Assertions.assertTrue(lease.hasNext()); - lease.next(); - } - - Assertions.assertEquals(32, i); - Assertions.assertFalse(w.hasRemaining()); - Assertions.assertFalse(lease.hasNext()); + Assertions.assertEquals(32, i); + Assertions.assertFalse(w.hasRemaining()); + Assertions.assertFalse(lease.hasNext()); - Assertions.assertThrows(IndexOutOfBoundsException.class, lease::next); + Assertions.assertThrows(IndexOutOfBoundsException.class, lease::next); + } } } From 2a54cd5fa512d1c7871872cdd12c2ce244dd900c Mon Sep 17 00:00:00 2001 From: eemhu <125959687+eemhu@users.noreply.github.com> Date: Thu, 30 Apr 2026 10:19:53 +0300 Subject: [PATCH 40/45] rename socket srcs to dsts --- .../net_01/channel/context/IngressImpl.java | 6 ++---- .../net_01/channel/socket/PlainSocket.java | 16 ++++++++-------- .../teragrep/net_01/channel/socket/Socket.java | 4 ++-- .../net_01/channel/socket/TLSSocket.java | 16 ++++++++-------- 4 files changed, 20 insertions(+), 22 deletions(-) diff --git a/src/main/java/com/teragrep/net_01/channel/context/IngressImpl.java b/src/main/java/com/teragrep/net_01/channel/context/IngressImpl.java index fdb51db..92234ff 100644 --- a/src/main/java/com/teragrep/net_01/channel/context/IngressImpl.java +++ b/src/main/java/com/teragrep/net_01/channel/context/IngressImpl.java @@ -228,11 +228,9 @@ else if (readBytes < 0) { } private long readData() throws IOException { - long readBytes; + final List> bufferLeases = new LeaseMultiGet(memorySegmentLeasePool).get(4); + final List> trackedMemorySegmentLeases = new LinkedList<>(); - List> bufferLeases = new LeaseMultiGet(memorySegmentLeasePool).get(4); - - List> trackedMemorySegmentLeases = new LinkedList<>(); for (OpenableLease bufferLease : bufferLeases) { if (bufferLease.isStub()) { continue; diff --git a/src/main/java/com/teragrep/net_01/channel/socket/PlainSocket.java b/src/main/java/com/teragrep/net_01/channel/socket/PlainSocket.java index 8abcd58..3ec32bd 100644 --- a/src/main/java/com/teragrep/net_01/channel/socket/PlainSocket.java +++ b/src/main/java/com/teragrep/net_01/channel/socket/PlainSocket.java @@ -67,19 +67,19 @@ final class PlainSocket implements Socket { } @Override - public ReadResult read(List> srcs) throws IOException { - final int size = srcs.size(); + public ReadResult read(List> dsts) throws IOException { + final int size = dsts.size(); final List> rv = new ArrayList<>(size); final ByteBuffer[] byteBuffers = new ByteBuffer[size]; for (int i = 0; i < size; i++) { - byteBuffers[i] = srcs.get(i).leasedObject().asByteBuffer(); + byteBuffers[i] = dsts.get(i).leasedObject().asByteBuffer(); } final long readBytes = socketChannel.read(byteBuffers); long bytesLeft = readBytes; boolean allRead = false; - for (final TrackedLease bufferLease : srcs) { + for (final TrackedLease bufferLease : dsts) { final long byteSize = bufferLease.leasedObject().byteSize(); if (!allRead && readBytes > 0) { @@ -108,20 +108,20 @@ public ReadResult read(List> srcs) throws IOExceptio } @Override - public WrittenResult write(List> leases) throws IOException { - final int size = leases.size(); + public WrittenResult write(List> dsts) throws IOException { + final int size = dsts.size(); final ByteBuffer[] buffersToWrite = new ByteBuffer[size]; final List> rv = new ArrayList<>(size); for (int i = 0; i < size; i++) { - buffersToWrite[i] = leases.get(i).leasedObject().asByteBuffer(); + buffersToWrite[i] = dsts.get(i).leasedObject().asByteBuffer(); } final long bytesWritten = socketChannel.write(buffersToWrite); long bytesLeft = bytesWritten; boolean allWritten = false; - for (final TrackedLease bufferLease : leases) { + for (final TrackedLease bufferLease : dsts) { final long byteSize = bufferLease.leasedObject().byteSize(); if (!allWritten && bytesWritten > 0) { diff --git a/src/main/java/com/teragrep/net_01/channel/socket/Socket.java b/src/main/java/com/teragrep/net_01/channel/socket/Socket.java index 75be296..611a929 100644 --- a/src/main/java/com/teragrep/net_01/channel/socket/Socket.java +++ b/src/main/java/com/teragrep/net_01/channel/socket/Socket.java @@ -60,11 +60,11 @@ public interface Socket { /** * Read data from a network connection. * - * @param srcs {@link TrackedLease}s which are read to from the connection + * @param dsts {@link TrackedLease}s which are read to from the connection * @return amount of bytes read * @throws IOException if read fails */ - ReadResult read(List> srcs) throws IOException; + ReadResult read(List> dsts) throws IOException; /** * Write data through a network connection. diff --git a/src/main/java/com/teragrep/net_01/channel/socket/TLSSocket.java b/src/main/java/com/teragrep/net_01/channel/socket/TLSSocket.java index b5440bc..12fe0ac 100644 --- a/src/main/java/com/teragrep/net_01/channel/socket/TLSSocket.java +++ b/src/main/java/com/teragrep/net_01/channel/socket/TLSSocket.java @@ -70,19 +70,19 @@ final class TLSSocket implements Socket { } @Override - public ReadResult read(List> srcs) throws IOException { - final int size = srcs.size(); + public ReadResult read(List> dsts) throws IOException { + final int size = dsts.size(); final List> rv = new ArrayList<>(size); final ByteBuffer[] byteBuffers = new ByteBuffer[size]; for (int i = 0; i < size; i++) { - byteBuffers[i] = srcs.get(i).leasedObject().asByteBuffer(); + byteBuffers[i] = dsts.get(i).leasedObject().asByteBuffer(); } final long readBytes = tlsChannel.read(byteBuffers); long bytesLeft = readBytes; boolean allRead = false; - for (final TrackedLease bufferLease : srcs) { + for (final TrackedLease bufferLease : dsts) { final long byteSize = bufferLease.leasedObject().byteSize(); if (!allRead && readBytes > 0) { @@ -111,20 +111,20 @@ public ReadResult read(List> srcs) throws IOExceptio } @Override - public WrittenResult write(List> leases) throws IOException { - final int size = leases.size(); + public WrittenResult write(List> dsts) throws IOException { + final int size = dsts.size(); final ByteBuffer[] buffersToWrite = new ByteBuffer[size]; final List> rv = new ArrayList<>(size); for (int i = 0; i < size; i++) { - buffersToWrite[i] = leases.get(i).leasedObject().asByteBuffer(); + buffersToWrite[i] = dsts.get(i).leasedObject().asByteBuffer(); } final long bytesWritten = tlsChannel.write(buffersToWrite); long bytesLeft = bytesWritten; boolean allWritten = false; - for (final TrackedLease bufferLease : leases) { + for (final TrackedLease bufferLease : dsts) { final long byteSize = bufferLease.leasedObject().byteSize(); if (!allWritten && bytesWritten > 0) { From 957332cc66af9165828cb497d8470700dfeb3a86 Mon Sep 17 00:00:00 2001 From: eemhu <125959687+eemhu@users.noreply.github.com> Date: Thu, 30 Apr 2026 12:15:26 +0300 Subject: [PATCH 41/45] replace most list instances with arrays --- .../channel/buffer/writable/Writeable.java | 3 +- .../buffer/writable/WriteableAccess.java | 3 +- .../buffer/writable/WriteableClosure.java | 3 +- .../writable/WriteableInvalidation.java | 3 +- .../buffer/writable/WriteableLeaseful.java | 2 +- .../buffer/writable/WriteableStub.java | 3 +- .../channel/buffer/writable/Writeables.java | 18 ++++++---- .../net_01/channel/context/EgressImpl.java | 15 ++++++-- .../net_01/channel/context/IngressImpl.java | 11 +++--- .../net_01/channel/socket/IOResult.java | 4 +-- .../net_01/channel/socket/PlainSocket.java | 35 ++++++++++--------- .../net_01/channel/socket/ReadResult.java | 7 ++-- .../net_01/channel/socket/Socket.java | 5 ++- .../net_01/channel/socket/TLSSocket.java | 35 ++++++++++--------- .../net_01/channel/socket/WrittenResult.java | 7 ++-- .../net_01/channel/StringToLease.java | 10 +++--- .../buffer/writable/WriteableTest.java | 21 ++++++----- .../channel/context/StringWriteable.java | 7 ++-- .../net_01/channel/socket/SocketFake.java | 11 +++--- .../net_01/channel/socket/SocketTest.java | 15 ++++---- 20 files changed, 113 insertions(+), 105 deletions(-) diff --git a/src/main/java/com/teragrep/net_01/channel/buffer/writable/Writeable.java b/src/main/java/com/teragrep/net_01/channel/buffer/writable/Writeable.java index 2018032..042840f 100644 --- a/src/main/java/com/teragrep/net_01/channel/buffer/writable/Writeable.java +++ b/src/main/java/com/teragrep/net_01/channel/buffer/writable/Writeable.java @@ -49,14 +49,13 @@ import java.io.Closeable; import java.lang.foreign.MemorySegment; -import java.util.List; public interface Writeable extends Closeable { @Override void close(); - List> memorySegmentLeases(); + TrackedLease[] memorySegmentLeases(); boolean hasRemaining(); diff --git a/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableAccess.java b/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableAccess.java index 4a49bf2..e3e7658 100644 --- a/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableAccess.java +++ b/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableAccess.java @@ -50,7 +50,6 @@ import com.teragrep.net_01.channel.buffer.access.Lease; import java.lang.foreign.MemorySegment; -import java.util.List; public final class WriteableAccess implements Writeable { @@ -63,7 +62,7 @@ public WriteableAccess(Writeable writeable, Access access) { } @Override - public List> memorySegmentLeases() { + public TrackedLease[] memorySegmentLeases() { // FIXME just not right try (Lease ignored = access.get()) { return writeable.memorySegmentLeases(); diff --git a/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableClosure.java b/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableClosure.java index 2b291d9..d373960 100644 --- a/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableClosure.java +++ b/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableClosure.java @@ -51,7 +51,6 @@ import org.slf4j.LoggerFactory; import java.lang.foreign.MemorySegment; -import java.util.List; /** * Closes a connection at close() @@ -83,7 +82,7 @@ public void close() { } @Override - public List> memorySegmentLeases() { + public TrackedLease[] memorySegmentLeases() { return writeable.memorySegmentLeases(); } diff --git a/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableInvalidation.java b/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableInvalidation.java index 3f6c16d..8bd939f 100644 --- a/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableInvalidation.java +++ b/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableInvalidation.java @@ -48,7 +48,6 @@ import com.teragrep.buf_01.buffer.lease.TrackedLease; import java.lang.foreign.MemorySegment; -import java.util.List; /** * Decoration of {@link Writeable} Invalidates a writable so TrackedLeases' position and limit is set to zero and the @@ -78,7 +77,7 @@ public void close() { } @Override - public List> memorySegmentLeases() { + public TrackedLease[] memorySegmentLeases() { return writeable.memorySegmentLeases(); } diff --git a/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableLeaseful.java b/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableLeaseful.java index 51688b9..7886465 100644 --- a/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableLeaseful.java +++ b/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableLeaseful.java @@ -66,7 +66,7 @@ public WriteableLeaseful(Writeable writeable, List> } @Override - public List> memorySegmentLeases() { + public TrackedLease[] memorySegmentLeases() { return writeable.memorySegmentLeases(); } diff --git a/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableStub.java b/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableStub.java index d37daf8..3e4ee9f 100644 --- a/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableStub.java +++ b/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableStub.java @@ -48,12 +48,11 @@ import com.teragrep.buf_01.buffer.lease.TrackedLease; import java.lang.foreign.MemorySegment; -import java.util.List; public final class WriteableStub implements Writeable { @Override - public List> memorySegmentLeases() { + public TrackedLease[] memorySegmentLeases() { throw new UnsupportedOperationException("WriteableStub does not allow this method"); } diff --git a/src/main/java/com/teragrep/net_01/channel/buffer/writable/Writeables.java b/src/main/java/com/teragrep/net_01/channel/buffer/writable/Writeables.java index c9a1bb2..2d61716 100644 --- a/src/main/java/com/teragrep/net_01/channel/buffer/writable/Writeables.java +++ b/src/main/java/com/teragrep/net_01/channel/buffer/writable/Writeables.java @@ -46,10 +46,9 @@ package com.teragrep.net_01.channel.buffer.writable; import com.teragrep.buf_01.buffer.lease.TrackedLease; +import com.teragrep.buf_01.buffer.lease.TrackedMemorySegmentLease; import java.lang.foreign.MemorySegment; -import java.util.ArrayList; -import java.util.List; public final class Writeables implements Writeable { @@ -60,10 +59,10 @@ public Writeables(Writeable ... writeables) { } @Override - public List> memorySegmentLeases() { + public TrackedLease[] memorySegmentLeases() { long totalBuffers = 0; for (Writeable writeable : writeables) { - totalBuffers = totalBuffers + writeable.memorySegmentLeases().size(); + totalBuffers = totalBuffers + writeable.memorySegmentLeases().length; } if (totalBuffers > Integer.MAX_VALUE) { @@ -72,9 +71,14 @@ public List> memorySegmentLeases() { ); } - List> bufferArray = new ArrayList<>((int) totalBuffers); - for (final Writeable writeable : writeables) { - bufferArray.addAll(writeable.memorySegmentLeases()); + TrackedLease[] bufferArray = new TrackedMemorySegmentLease[(int) totalBuffers]; + + int i = 0; + for (final Writeable w : writeables) { + for (final TrackedLease lease : w.memorySegmentLeases()) { + bufferArray[i] = lease; + i++; + } } return bufferArray; diff --git a/src/main/java/com/teragrep/net_01/channel/context/EgressImpl.java b/src/main/java/com/teragrep/net_01/channel/context/EgressImpl.java index 5d35488..32bca2a 100644 --- a/src/main/java/com/teragrep/net_01/channel/context/EgressImpl.java +++ b/src/main/java/com/teragrep/net_01/channel/context/EgressImpl.java @@ -46,6 +46,7 @@ package com.teragrep.net_01.channel.context; import com.teragrep.buf_01.buffer.lease.TrackedLease; +import com.teragrep.buf_01.buffer.lease.TrackedMemorySegmentLease; import com.teragrep.net_01.channel.buffer.writable.Writeable; import com.teragrep.net_01.channel.buffer.writable.WriteableStub; import com.teragrep.net_01.channel.socket.WrittenResult; @@ -164,12 +165,20 @@ public void accept(Writeable writeable) { } private void transmit(final List toWriteList) throws IOException { - try { - final List> writeBuffers = new ArrayList<>(); + int numberOfBuffers = 0; + for (final Writeable w : toWriteList) { + numberOfBuffers += w.memorySegmentLeases().length; + } + final TrackedLease[] writeBuffers = new TrackedMemorySegmentLease[numberOfBuffers]; + + int i = 0; for (final Writeable w : toWriteList) { - writeBuffers.addAll(w.memorySegmentLeases()); + for (final TrackedLease lease : w.memorySegmentLeases()) { + writeBuffers[i] = lease; + i++; + } writeInProgressList.add(w); } diff --git a/src/main/java/com/teragrep/net_01/channel/context/IngressImpl.java b/src/main/java/com/teragrep/net_01/channel/context/IngressImpl.java index 92234ff..1fb7dcc 100644 --- a/src/main/java/com/teragrep/net_01/channel/context/IngressImpl.java +++ b/src/main/java/com/teragrep/net_01/channel/context/IngressImpl.java @@ -59,6 +59,7 @@ import java.io.IOException; import java.lang.foreign.MemorySegment; import java.nio.channels.CancelledKeyException; +import java.util.Arrays; import java.util.Collections; import java.util.LinkedList; import java.util.List; @@ -229,18 +230,20 @@ else if (readBytes < 0) { private long readData() throws IOException { final List> bufferLeases = new LeaseMultiGet(memorySegmentLeasePool).get(4); - final List> trackedMemorySegmentLeases = new LinkedList<>(); + final int size = bufferLeases.size(); + final TrackedLease[] trackedMemorySegmentLeases = new TrackedMemorySegmentLease[size]; - for (OpenableLease bufferLease : bufferLeases) { + for (int i = 0; i < size; i++) { + final OpenableLease bufferLease = bufferLeases.get(i); if (bufferLease.isStub()) { continue; } - trackedMemorySegmentLeases.add(new TrackedMemorySegmentLease(bufferLease)); + trackedMemorySegmentLeases[i] = new TrackedMemorySegmentLease(bufferLease); } final ReadResult result = establishedContext.socket().read(trackedMemorySegmentLeases); - activeBuffers.addAll(result.leases()); + activeBuffers.addAll(Arrays.asList(result.leases())); LOGGER.debug("establishedContext.read got <{}> bytes from socket", result.bytes()); diff --git a/src/main/java/com/teragrep/net_01/channel/socket/IOResult.java b/src/main/java/com/teragrep/net_01/channel/socket/IOResult.java index 247247d..3fc01fb 100644 --- a/src/main/java/com/teragrep/net_01/channel/socket/IOResult.java +++ b/src/main/java/com/teragrep/net_01/channel/socket/IOResult.java @@ -47,11 +47,9 @@ import com.teragrep.buf_01.buffer.lease.Lease; -import java.util.List; - public interface IOResult> { public abstract long bytes(); - public abstract List leases(); + public abstract T[] leases(); } diff --git a/src/main/java/com/teragrep/net_01/channel/socket/PlainSocket.java b/src/main/java/com/teragrep/net_01/channel/socket/PlainSocket.java index 3ec32bd..9bdd01d 100644 --- a/src/main/java/com/teragrep/net_01/channel/socket/PlainSocket.java +++ b/src/main/java/com/teragrep/net_01/channel/socket/PlainSocket.java @@ -52,8 +52,6 @@ import java.lang.foreign.MemorySegment; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; -import java.util.ArrayList; -import java.util.List; final class PlainSocket implements Socket { @@ -67,19 +65,20 @@ final class PlainSocket implements Socket { } @Override - public ReadResult read(List> dsts) throws IOException { - final int size = dsts.size(); - final List> rv = new ArrayList<>(size); + public ReadResult read(final TrackedLease[] dsts) throws IOException { + final int size = dsts.length; + final TrackedLease[] rv = new TrackedMemorySegmentLease[size]; final ByteBuffer[] byteBuffers = new ByteBuffer[size]; for (int i = 0; i < size; i++) { - byteBuffers[i] = dsts.get(i).leasedObject().asByteBuffer(); + byteBuffers[i] = dsts[i].leasedObject().asByteBuffer(); } final long readBytes = socketChannel.read(byteBuffers); long bytesLeft = readBytes; boolean allRead = false; - for (final TrackedLease bufferLease : dsts) { + for (int i = 0; i < size; i++) { + final TrackedLease bufferLease = dsts[i]; final long byteSize = bufferLease.leasedObject().byteSize(); if (!allRead && readBytes > 0) { @@ -89,11 +88,13 @@ public ReadResult read(List> dsts) throws IOExceptio // mem.segment bigger than bytes left. // set limit to read amount. final long limit = byteSize - Math.abs(diff); - rv.add(new TrackedMemorySegmentLease(bufferLease, 0L, limit)); + bufferLease.position(0L); + bufferLease.limit(limit); + rv[i] = bufferLease; } else { //else: full mem.segment used, no need to set limit. - rv.add(new TrackedMemorySegmentLease(bufferLease)); + rv[i] = bufferLease; } } @@ -108,20 +109,22 @@ public ReadResult read(List> dsts) throws IOExceptio } @Override - public WrittenResult write(List> dsts) throws IOException { - final int size = dsts.size(); + public WrittenResult write(final TrackedLease[] dsts) throws IOException { + final int size = dsts.length; final ByteBuffer[] buffersToWrite = new ByteBuffer[size]; - final List> rv = new ArrayList<>(size); + final TrackedLease[] rv = new TrackedMemorySegmentLease[size]; for (int i = 0; i < size; i++) { - buffersToWrite[i] = dsts.get(i).leasedObject().asByteBuffer(); + buffersToWrite[i] = dsts[i].leasedObject().asByteBuffer(); } final long bytesWritten = socketChannel.write(buffersToWrite); long bytesLeft = bytesWritten; boolean allWritten = false; - for (final TrackedLease bufferLease : dsts) { + + for (int i = 0; i < size; i++) { + final TrackedLease bufferLease = dsts[i]; final long byteSize = bufferLease.leasedObject().byteSize(); if (!allWritten && bytesWritten > 0) { @@ -133,11 +136,11 @@ public WrittenResult write(List> dsts) throws IOExce final long limit = byteSize - Math.abs(diff); bufferLease.position(0L); bufferLease.limit(limit); - rv.add(bufferLease); + rv[i] = bufferLease; } else { //else: full mem.segment used, no need to set limit. - rv.add(bufferLease); + rv[i] = bufferLease; } } diff --git a/src/main/java/com/teragrep/net_01/channel/socket/ReadResult.java b/src/main/java/com/teragrep/net_01/channel/socket/ReadResult.java index c5a10ed..7324b47 100644 --- a/src/main/java/com/teragrep/net_01/channel/socket/ReadResult.java +++ b/src/main/java/com/teragrep/net_01/channel/socket/ReadResult.java @@ -48,14 +48,13 @@ import com.teragrep.buf_01.buffer.lease.TrackedLease; import java.lang.foreign.MemorySegment; -import java.util.List; public final class ReadResult implements IOResult> { private final long bytesRead; - private final List> leases; + private final TrackedLease[] leases; - public ReadResult(final long bytesRead, final List> leases) { + public ReadResult(final long bytesRead, final TrackedLease[] leases) { this.bytesRead = bytesRead; this.leases = leases; } @@ -66,7 +65,7 @@ public long bytes() { } @Override - public List> leases() { + public TrackedLease[] leases() { return leases; } } diff --git a/src/main/java/com/teragrep/net_01/channel/socket/Socket.java b/src/main/java/com/teragrep/net_01/channel/socket/Socket.java index 611a929..e42d058 100644 --- a/src/main/java/com/teragrep/net_01/channel/socket/Socket.java +++ b/src/main/java/com/teragrep/net_01/channel/socket/Socket.java @@ -50,7 +50,6 @@ import java.io.IOException; import java.lang.foreign.MemorySegment; import java.nio.channels.SocketChannel; -import java.util.List; /** * {@link Socket} provides network connectivity methods @@ -64,7 +63,7 @@ public interface Socket { * @return amount of bytes read * @throws IOException if read fails */ - ReadResult read(List> dsts) throws IOException; + ReadResult read(TrackedLease[] dsts) throws IOException; /** * Write data through a network connection. @@ -73,7 +72,7 @@ public interface Socket { * @return amount of bytes written * @throws IOException if write fails */ - WrittenResult write(List> dsts) throws IOException; + WrittenResult write(TrackedLease[] dsts) throws IOException; /** * Provides information about a network connection diff --git a/src/main/java/com/teragrep/net_01/channel/socket/TLSSocket.java b/src/main/java/com/teragrep/net_01/channel/socket/TLSSocket.java index 12fe0ac..586c49f 100644 --- a/src/main/java/com/teragrep/net_01/channel/socket/TLSSocket.java +++ b/src/main/java/com/teragrep/net_01/channel/socket/TLSSocket.java @@ -53,8 +53,6 @@ import java.lang.foreign.MemorySegment; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; -import java.util.ArrayList; -import java.util.List; final class TLSSocket implements Socket { @@ -70,19 +68,20 @@ final class TLSSocket implements Socket { } @Override - public ReadResult read(List> dsts) throws IOException { - final int size = dsts.size(); - final List> rv = new ArrayList<>(size); + public ReadResult read(final TrackedLease[] dsts) throws IOException { + final int size = dsts.length; + final TrackedLease[] rv = new TrackedMemorySegmentLease[size]; final ByteBuffer[] byteBuffers = new ByteBuffer[size]; for (int i = 0; i < size; i++) { - byteBuffers[i] = dsts.get(i).leasedObject().asByteBuffer(); + byteBuffers[i] = dsts[i].leasedObject().asByteBuffer(); } final long readBytes = tlsChannel.read(byteBuffers); long bytesLeft = readBytes; boolean allRead = false; - for (final TrackedLease bufferLease : dsts) { + for (int i = 0; i < size; i++) { + final TrackedLease bufferLease = dsts[i]; final long byteSize = bufferLease.leasedObject().byteSize(); if (!allRead && readBytes > 0) { @@ -92,11 +91,13 @@ public ReadResult read(List> dsts) throws IOExceptio // mem.segment bigger than bytes left. // set limit to read amount. final long limit = byteSize - Math.abs(diff); - rv.add(new TrackedMemorySegmentLease(bufferLease, 0L, limit)); + bufferLease.position(0L); + bufferLease.limit(limit); + rv[i] = bufferLease; } else { //else: full mem.segment used, no need to set limit. - rv.add(new TrackedMemorySegmentLease(bufferLease)); + rv[i] = bufferLease; } } @@ -111,20 +112,22 @@ public ReadResult read(List> dsts) throws IOExceptio } @Override - public WrittenResult write(List> dsts) throws IOException { - final int size = dsts.size(); + public WrittenResult write(final TrackedLease[] dsts) throws IOException { + final int size = dsts.length; final ByteBuffer[] buffersToWrite = new ByteBuffer[size]; - final List> rv = new ArrayList<>(size); + final TrackedLease[] rv = new TrackedMemorySegmentLease[size]; for (int i = 0; i < size; i++) { - buffersToWrite[i] = dsts.get(i).leasedObject().asByteBuffer(); + buffersToWrite[i] = dsts[i].leasedObject().asByteBuffer(); } final long bytesWritten = tlsChannel.write(buffersToWrite); long bytesLeft = bytesWritten; boolean allWritten = false; - for (final TrackedLease bufferLease : dsts) { + + for (int i = 0; i < size; i++) { + final TrackedLease bufferLease = dsts[i]; final long byteSize = bufferLease.leasedObject().byteSize(); if (!allWritten && bytesWritten > 0) { @@ -136,11 +139,11 @@ public WrittenResult write(List> dsts) throws IOExce final long limit = byteSize - Math.abs(diff); bufferLease.position(0L); bufferLease.limit(limit); - rv.add(bufferLease); + rv[i] = bufferLease; } else { //else: full mem.segment used, no need to set limit. - rv.add(bufferLease); + rv[i] = bufferLease; } } diff --git a/src/main/java/com/teragrep/net_01/channel/socket/WrittenResult.java b/src/main/java/com/teragrep/net_01/channel/socket/WrittenResult.java index e198f4f..7b1e2d2 100644 --- a/src/main/java/com/teragrep/net_01/channel/socket/WrittenResult.java +++ b/src/main/java/com/teragrep/net_01/channel/socket/WrittenResult.java @@ -48,14 +48,13 @@ import com.teragrep.buf_01.buffer.lease.TrackedLease; import java.lang.foreign.MemorySegment; -import java.util.List; public class WrittenResult implements IOResult> { private final long bytesWritten; - private final List> leases; + private final TrackedLease[] leases; - public WrittenResult(final long bytesWritten, final List> leases) { + public WrittenResult(final long bytesWritten, final TrackedLease[] leases) { this.bytesWritten = bytesWritten; this.leases = leases; } @@ -66,7 +65,7 @@ public long bytes() { } @Override - public List> leases() { + public TrackedLease[] leases() { return leases; } } diff --git a/src/test/java/com/teragrep/net_01/channel/StringToLease.java b/src/test/java/com/teragrep/net_01/channel/StringToLease.java index 94da068..491c363 100644 --- a/src/test/java/com/teragrep/net_01/channel/StringToLease.java +++ b/src/test/java/com/teragrep/net_01/channel/StringToLease.java @@ -55,7 +55,6 @@ import java.lang.foreign.MemorySegment; import java.nio.charset.StandardCharsets; -import java.util.ArrayList; import java.util.List; public final class StringToLease { @@ -72,12 +71,13 @@ public Writeable toWriteable() { return new StringWriteable(toLeases()); } - public List> toLeases() { + public TrackedLease[] toLeases() { final byte[] bytes = origin.getBytes(StandardCharsets.UTF_8); final List> leases = new LeaseMultiGet(pool).get(bytes.length); - final List> trackedLeases = new ArrayList<>(leases.size()); - for (final OpenableLease lease : leases) { - trackedLeases.add(new TrackedMemorySegmentLease(lease)); + final TrackedLease[] trackedLeases = new TrackedMemorySegmentLease[leases.size()]; + + for (int i = 0; i < leases.size(); i++) { + trackedLeases[i] = new TrackedMemorySegmentLease(leases.get(i)); } int i = 0; diff --git a/src/test/java/com/teragrep/net_01/channel/buffer/writable/WriteableTest.java b/src/test/java/com/teragrep/net_01/channel/buffer/writable/WriteableTest.java index 14bab07..9a94c5f 100644 --- a/src/test/java/com/teragrep/net_01/channel/buffer/writable/WriteableTest.java +++ b/src/test/java/com/teragrep/net_01/channel/buffer/writable/WriteableTest.java @@ -59,7 +59,6 @@ import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; -import java.util.ArrayList; import java.util.List; public final class WriteableTest { @@ -71,16 +70,16 @@ void testWriteableHasRemaining() { ); final List> leases = new LeaseMultiGet(pool).get(32L); - final List> trackedLeases = new ArrayList<>(leases.size()); + final TrackedLease[] trackedLeases = new TrackedMemorySegmentLease[leases.size()]; - for (final OpenableLease lease : leases) { - trackedLeases.add(new TrackedMemorySegmentLease(lease)); + for (int i = 0; i < leases.size(); i++) { + trackedLeases[i] = new TrackedMemorySegmentLease(leases.get(i)); } try (final Writeable w = new StringWriteable(trackedLeases)) { Assertions.assertEquals(trackedLeases, w.memorySegmentLeases()); - Assertions.assertEquals(1, w.memorySegmentLeases().size()); - final TrackedLease lease = trackedLeases.getFirst(); + Assertions.assertEquals(1, w.memorySegmentLeases().length); + final TrackedLease lease = trackedLeases[0]; int i; for (i = 0; i < 128; i++) { @@ -104,16 +103,16 @@ void testWriteableHasRemainingWithSetLimit() { ); final List> leases = new LeaseMultiGet(pool).get(32L); - final List> trackedLeases = new ArrayList<>(leases.size()); + final TrackedLease[] trackedLeases = new TrackedMemorySegmentLease[leases.size()]; - for (final OpenableLease lease : leases) { - trackedLeases.add(new TrackedMemorySegmentLease(lease)); + for (int i = 0; i < leases.size(); i++) { + trackedLeases[i] = new TrackedMemorySegmentLease(leases.get(i)); } try (final Writeable w = new StringWriteable(trackedLeases)) { Assertions.assertEquals(trackedLeases, w.memorySegmentLeases()); - Assertions.assertEquals(1, w.memorySegmentLeases().size()); - final TrackedLease lease = trackedLeases.getFirst(); + Assertions.assertEquals(1, w.memorySegmentLeases().length); + final TrackedLease lease = trackedLeases[0]; lease.limit(32L); int i; diff --git a/src/test/java/com/teragrep/net_01/channel/context/StringWriteable.java b/src/test/java/com/teragrep/net_01/channel/context/StringWriteable.java index 087a669..4c91405 100644 --- a/src/test/java/com/teragrep/net_01/channel/context/StringWriteable.java +++ b/src/test/java/com/teragrep/net_01/channel/context/StringWriteable.java @@ -49,13 +49,12 @@ import com.teragrep.net_01.channel.buffer.writable.Writeable; import java.lang.foreign.MemorySegment; -import java.util.List; public final class StringWriteable implements Writeable { - private final List> buffers; + private final TrackedLease[] buffers; - public StringWriteable(final List> buffers) { + public StringWriteable(final TrackedLease[] buffers) { this.buffers = buffers; } @@ -72,7 +71,7 @@ public void close() { } @Override - public List> memorySegmentLeases() { + public TrackedLease[] memorySegmentLeases() { return buffers; } diff --git a/src/test/java/com/teragrep/net_01/channel/socket/SocketFake.java b/src/test/java/com/teragrep/net_01/channel/socket/SocketFake.java index 695a736..b24954b 100644 --- a/src/test/java/com/teragrep/net_01/channel/socket/SocketFake.java +++ b/src/test/java/com/teragrep/net_01/channel/socket/SocketFake.java @@ -46,11 +46,10 @@ package com.teragrep.net_01.channel.socket; import com.teragrep.buf_01.buffer.lease.TrackedLease; +import com.teragrep.buf_01.buffer.lease.TrackedMemorySegmentLease; import java.lang.foreign.MemorySegment; import java.nio.channels.SocketChannel; -import java.util.Collections; -import java.util.List; public class SocketFake implements Socket { @@ -61,13 +60,13 @@ public SocketFake() { } @Override - public ReadResult read(List> dsts) { - return new ReadResult(0, Collections.emptyList()); + public ReadResult read(TrackedLease[] dsts) { + return new ReadResult(0, new TrackedMemorySegmentLease[0]); } @Override - public WrittenResult write(List> dsts) { - return new WrittenResult(0, Collections.emptyList()); + public WrittenResult write(TrackedLease[] dsts) { + return new WrittenResult(0, new TrackedMemorySegmentLease[0]); } @Override diff --git a/src/test/java/com/teragrep/net_01/channel/socket/SocketTest.java b/src/test/java/com/teragrep/net_01/channel/socket/SocketTest.java index 3296989..b10ee0c 100644 --- a/src/test/java/com/teragrep/net_01/channel/socket/SocketTest.java +++ b/src/test/java/com/teragrep/net_01/channel/socket/SocketTest.java @@ -63,7 +63,6 @@ import java.lang.foreign.MemorySegment; import java.net.InetSocketAddress; import java.nio.channels.ServerSocketChannel; -import java.util.ArrayList; import java.util.List; @TestInstance(TestInstance.Lifecycle.PER_CLASS) @@ -146,7 +145,7 @@ void testPlainSocketRead() { out.println("worldHello"); - List> bufs = emptyBuffers(10); + TrackedLease[] bufs = emptyBuffers(10); ReadResult res = socket.read(bufs); Assertions.assertEquals("worldHello\n", bufferToString(res.leases())); @@ -157,7 +156,7 @@ void testPlainSocketRead() { }); } - private String bufferToString(final List> leases) { + private String bufferToString(final TrackedLease[] leases) { final StringBuilder stringBuilder = new StringBuilder(); for (final TrackedLease buf : leases) { while (buf.hasNext()) { @@ -167,13 +166,13 @@ private String bufferToString(final List> leases) { return stringBuilder.toString(); } - private List> emptyBuffers(final int bytes) { + private TrackedLease[] emptyBuffers(final int bytes) { final List> leases = new LeaseMultiGet(pool).get(bytes); - final List> rv = new ArrayList<>(leases.size()); + final TrackedLease[] rv = new TrackedMemorySegmentLease[leases.size()]; - leases.forEach(lease -> { - rv.add(new TrackedMemorySegmentLease(lease)); - }); + for (int i = 0; i < leases.size(); i++) { + rv[i] = new TrackedMemorySegmentLease(leases.get(i)); + } return rv; } From 2379e329d6c98cfef5b93f4f1284a775d170473c Mon Sep 17 00:00:00 2001 From: eemhu <125959687+eemhu@users.noreply.github.com> Date: Thu, 30 Apr 2026 13:45:45 +0300 Subject: [PATCH 42/45] remove log from WriteableClosure --- .../net_01/channel/buffer/writable/WriteableClosure.java | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableClosure.java b/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableClosure.java index d373960..a8e3aeb 100644 --- a/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableClosure.java +++ b/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableClosure.java @@ -69,14 +69,6 @@ public WriteableClosure(Writeable writeable, EstablishedContext establishedConte @Override public void close() { - if (LOGGER.isDebugEnabled()) { - LOGGER - .debug( - "Sent command <{}>, Closing connection to PeerAddress <{}> PeerPort <{}>", "serverclose", - establishedContext.socket().getTransportInfo().getPeerAddress(), - establishedContext.socket().getTransportInfo().getPeerPort() - ); - } establishedContext.close(); writeable.close(); } From 6391eca1ef7b5c050969fe030783fbbd5736c368 Mon Sep 17 00:00:00 2001 From: eemhu <125959687+eemhu@users.noreply.github.com> Date: Thu, 30 Apr 2026 14:03:07 +0300 Subject: [PATCH 43/45] IngressImpl. change activeBuffers.add to .addFirst to be consistent with .removeFirst operation. --- .../java/com/teragrep/net_01/channel/context/IngressImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/teragrep/net_01/channel/context/IngressImpl.java b/src/main/java/com/teragrep/net_01/channel/context/IngressImpl.java index 1fb7dcc..93bf04a 100644 --- a/src/main/java/com/teragrep/net_01/channel/context/IngressImpl.java +++ b/src/main/java/com/teragrep/net_01/channel/context/IngressImpl.java @@ -137,7 +137,7 @@ public void run() { if (bufferLease.hasNext()) { // return back as it has some remaining LOGGER.debug("pushBack bufferLease id <{}>", bufferLease.id()); - activeBuffers.add(bufferLease); + activeBuffers.addFirst(bufferLease); if (LOGGER.isDebugEnabled()) { LOGGER .debug( From 5058047615b564baa05d4284b8a906d45ba485cc Mon Sep 17 00:00:00 2001 From: eemhu <125959687+eemhu@users.noreply.github.com> Date: Thu, 30 Apr 2026 14:55:20 +0300 Subject: [PATCH 44/45] fix debug messages to debug level --- .../java/com/teragrep/net_01/channel/context/EgressImpl.java | 2 +- src/main/java/com/teragrep/net_01/eventloop/EventLoop.java | 2 +- src/main/java/com/teragrep/net_01/server/ServerFactory.java | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/teragrep/net_01/channel/context/EgressImpl.java b/src/main/java/com/teragrep/net_01/channel/context/EgressImpl.java index 32bca2a..b4d2be8 100644 --- a/src/main/java/com/teragrep/net_01/channel/context/EgressImpl.java +++ b/src/main/java/com/teragrep/net_01/channel/context/EgressImpl.java @@ -182,7 +182,7 @@ private void transmit(final List toWriteList) throws IOException { writeInProgressList.add(w); } - LOGGER.info("Writing to socket"); + LOGGER.debug("Writing to socket"); final WrittenResult result = establishedContext.socket().write(writeBuffers); diff --git a/src/main/java/com/teragrep/net_01/eventloop/EventLoop.java b/src/main/java/com/teragrep/net_01/eventloop/EventLoop.java index b4678c8..0b3910c 100644 --- a/src/main/java/com/teragrep/net_01/eventloop/EventLoop.java +++ b/src/main/java/com/teragrep/net_01/eventloop/EventLoop.java @@ -93,7 +93,7 @@ public void register(Context context) { } private void registerPendingRegistrations() { - LOGGER.info("register pending regs"); + LOGGER.debug("register pending regs"); while (true) { Context context = pendingContextRegistrations.poll(); if (context != null) { diff --git a/src/main/java/com/teragrep/net_01/server/ServerFactory.java b/src/main/java/com/teragrep/net_01/server/ServerFactory.java index 5f5cabb..74e7672 100644 --- a/src/main/java/com/teragrep/net_01/server/ServerFactory.java +++ b/src/main/java/com/teragrep/net_01/server/ServerFactory.java @@ -98,9 +98,9 @@ public Server create(int port) throws IOException { ); ListenContext listenContext = listenContextFactory.open(new InetSocketAddress(port)); - LOGGER.info("registering to eventLoop <{}>", eventLoop); + LOGGER.debug("registering to eventLoop <{}>", eventLoop); eventLoop.register(listenContext); - LOGGER.info("registered to eventLoop <{}>", eventLoop); + LOGGER.debug("registered to eventLoop <{}>", eventLoop); return new Server(listenContext); } } From 3381420cb47d8263d1006516027a0e44f5c6a196 Mon Sep 17 00:00:00 2001 From: eemhu <125959687+eemhu@users.noreply.github.com> Date: Thu, 30 Apr 2026 15:05:15 +0300 Subject: [PATCH 45/45] remove FIXME from WriteableLeaseful --- .../net_01/channel/buffer/writable/WriteableLeaseful.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableLeaseful.java b/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableLeaseful.java index 7886465..5e57d6e 100644 --- a/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableLeaseful.java +++ b/src/main/java/com/teragrep/net_01/channel/buffer/writable/WriteableLeaseful.java @@ -86,9 +86,9 @@ public void close() { // TODO subleases for fragments for (OpenableLease bufferLease : leases) { if (LOGGER.isDebugEnabled()) { - LOGGER.debug("releasing id <{}> with refs <{}>", bufferLease.id(), bufferLease.refs()); + LOGGER.debug("closing id <{}> with refs <{}>", bufferLease.id(), bufferLease.refs()); } - // FIXME: bufferLease.removeRef(); + try { bufferLease.close(); }