diff --git a/src/main/java/com/teragrep/buf_01/buffer/lease/Lease.java b/src/main/java/com/teragrep/buf_01/buffer/lease/Lease.java index ea9f6ee..a5742fd 100644 --- a/src/main/java/com/teragrep/buf_01/buffer/lease/Lease.java +++ b/src/main/java/com/teragrep/buf_01/buffer/lease/Lease.java @@ -110,4 +110,7 @@ public interface Lease extends AutoCloseable, Stubable { * @return slice of the lease, registered as a sublease. */ public abstract Lease sliceAt(long offset); + + @Override + public abstract void close(); } diff --git a/src/main/java/com/teragrep/buf_01/buffer/lease/TrackedMemorySegmentLease.java b/src/main/java/com/teragrep/buf_01/buffer/lease/TrackedMemorySegmentLease.java index 59306da..d23f343 100644 --- a/src/main/java/com/teragrep/buf_01/buffer/lease/TrackedMemorySegmentLease.java +++ b/src/main/java/com/teragrep/buf_01/buffer/lease/TrackedMemorySegmentLease.java @@ -143,7 +143,7 @@ public boolean isStub() { } @Override - public void close() throws Exception { + public void close() { origin.close(); } diff --git a/src/main/java/com/teragrep/buf_01/buffer/pool/LeaseMultiGet.java b/src/main/java/com/teragrep/buf_01/buffer/pool/LeaseMultiGet.java index 9337ab6..ed02b2c 100644 --- a/src/main/java/com/teragrep/buf_01/buffer/pool/LeaseMultiGet.java +++ b/src/main/java/com/teragrep/buf_01/buffer/pool/LeaseMultiGet.java @@ -45,6 +45,7 @@ */ package com.teragrep.buf_01.buffer.pool; +import com.teragrep.buf_01.buffer.lease.MemorySegmentLease; import com.teragrep.buf_01.buffer.lease.OpenableLease; import com.teragrep.poj_01.pool.Pool; @@ -89,9 +90,12 @@ public LeaseMultiGet(final Pool> leasePool) { } @Override - public List> get(final long bytesCount) { + public List> getAsList(final long bytesCount) { + // We don't know how many leases we will get in advance + // Need to use a list and expand if necessary long currentSize = 0; final List> leases = new ArrayList<>(); + while (currentSize < bytesCount) { final OpenableLease lease = leasePool.get(); if (lease.isStub()) { @@ -100,9 +104,23 @@ public List> get(final long bytesCount) { leases.add(lease); currentSize += lease.leasedObject().byteSize(); } + return leases; } + @Override + public OpenableLease[] getAsArray(final long bytesCount) { + final List> leases = getAsList(bytesCount); + final int size = leases.size(); + final OpenableLease[] rv = new MemorySegmentLease[size]; + + for (int i = 0; i < size; i++) { + rv[i] = leases.get(i); + } + + return rv; + } + @Override public boolean equals(final Object o) { if (o == null || getClass() != o.getClass()) { diff --git a/src/main/java/com/teragrep/buf_01/buffer/pool/MultiGet.java b/src/main/java/com/teragrep/buf_01/buffer/pool/MultiGet.java index 9575bb1..f342b49 100644 --- a/src/main/java/com/teragrep/buf_01/buffer/pool/MultiGet.java +++ b/src/main/java/com/teragrep/buf_01/buffer/pool/MultiGet.java @@ -45,9 +45,10 @@ */ package com.teragrep.buf_01.buffer.pool; +// spotless:off + import java.util.List; -// spotless:off /** * @interface MultiGet * @brief Provides an interface for getting multiples of the given type. @@ -72,5 +73,7 @@ // spotless:on public interface MultiGet { - public abstract List get(long count); + public abstract List getAsList(final long count); + + public abstract T[] getAsArray(final long count); } diff --git a/src/main/java/com/teragrep/buf_01/buffer/pool/TrackedLeaseMultiGet.java b/src/main/java/com/teragrep/buf_01/buffer/pool/TrackedLeaseMultiGet.java new file mode 100644 index 0000000..a80f88c --- /dev/null +++ b/src/main/java/com/teragrep/buf_01/buffer/pool/TrackedLeaseMultiGet.java @@ -0,0 +1,103 @@ +/* + * Teragrep Buffer Library for Java + * Copyright (C) 2026 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.buf_01.buffer.pool; + +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 java.lang.foreign.MemorySegment; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +public final class TrackedLeaseMultiGet implements MultiGet> { + + private final MultiGet> origin; + + public TrackedLeaseMultiGet(final MultiGet> origin) { + this.origin = origin; + } + + @Override + public List> getAsList(final long count) { + final List> leases = origin.getAsList(count); + final List> rv = new ArrayList<>(leases.size()); + + leases.forEach(lease -> { + rv.add(new TrackedMemorySegmentLease(lease)); + }); + + return rv; + } + + @Override + public TrackedLease[] getAsArray(final long count) { + final OpenableLease[] leases = origin.getAsArray(count); + final int len = leases.length; + final TrackedLease[] rv = new TrackedMemorySegmentLease[len]; + + for (int i = 0; i < len; i++) { + rv[i] = new TrackedMemorySegmentLease(leases[i]); + } + + return rv; + } + + @Override + public boolean equals(final Object o) { + if (o == null || getClass() != o.getClass()) { + return false; + } + final TrackedLeaseMultiGet that = (TrackedLeaseMultiGet) o; + return Objects.equals(origin, that.origin); + } + + @Override + public int hashCode() { + return Objects.hashCode(origin); + } +} diff --git a/src/test/java/com/teragrep/buf_01/buffer/LeaseMultiGetTest.java b/src/test/java/com/teragrep/buf_01/buffer/LeaseMultiGetTest.java index fdbfc1e..0854936 100644 --- a/src/test/java/com/teragrep/buf_01/buffer/LeaseMultiGetTest.java +++ b/src/test/java/com/teragrep/buf_01/buffer/LeaseMultiGetTest.java @@ -60,6 +60,7 @@ import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; +import java.util.Arrays; import java.util.List; final class LeaseMultiGetTest { @@ -71,10 +72,14 @@ void testTakeOneLease() { new UnboundPool<>(new ArenaMemorySegmentLeaseSupplier(Arena.ofShared(), 5), new MemorySegmentLeaseStub()) ); final MultiGet> multiGet = new LeaseMultiGet(pool); - final List> leases = multiGet.get(5); + final OpenableLease[] leases = multiGet.getAsArray(5); + final List> leasesList = multiGet.getAsList(5); - Assertions.assertEquals(1, leases.size()); - Assertions.assertEquals(5, leases.getFirst().leasedObject().byteSize()); + Assertions.assertEquals(1, leases.length); + Assertions.assertEquals(5, leases[0].leasedObject().byteSize()); + + Assertions.assertEquals(1, leasesList.size()); + Assertions.assertEquals(5, leasesList.getFirst().leasedObject().byteSize()); } @Test @@ -84,11 +89,16 @@ void testTakeTwoLeases() { new UnboundPool<>(new ArenaMemorySegmentLeaseSupplier(Arena.ofShared(), 3), new MemorySegmentLeaseStub()) ); final MultiGet> multiGet = new LeaseMultiGet(pool); - final List> leases = multiGet.get(5); + final OpenableLease[] leases = multiGet.getAsArray(5); + final List> leasesList = multiGet.getAsList(5); + + Assertions.assertEquals(2, leases.length); + Assertions.assertEquals(3, leases[0].leasedObject().byteSize()); + Assertions.assertEquals(3, leases[leases.length - 1].leasedObject().byteSize()); - Assertions.assertEquals(2, leases.size()); - Assertions.assertEquals(3, leases.getFirst().leasedObject().byteSize()); - Assertions.assertEquals(3, leases.getLast().leasedObject().byteSize()); + Assertions.assertEquals(2, leasesList.size()); + Assertions.assertEquals(3, leasesList.getFirst().leasedObject().byteSize()); + Assertions.assertEquals(3, leasesList.getLast().leasedObject().byteSize()); } @Test @@ -98,10 +108,14 @@ void testTakeFourLeases() { new UnboundPool<>(new ArenaMemorySegmentLeaseSupplier(Arena.ofShared(), 3), new MemorySegmentLeaseStub()) ); final MultiGet> multiGet = new LeaseMultiGet(pool); - final List> leases = multiGet.get(10); + final OpenableLease[] leases = multiGet.getAsArray(10); + final List> leasesList = multiGet.getAsList(10); + + Assertions.assertEquals(4, leases.length); + Assertions.assertEquals(4, Arrays.stream(leases).filter(l -> 3 == l.leasedObject().byteSize()).count()); - Assertions.assertEquals(4, leases.size()); - Assertions.assertEquals(4, leases.stream().filter(l -> 3 == l.leasedObject().byteSize()).count()); + Assertions.assertEquals(4, leasesList.size()); + Assertions.assertEquals(4, leasesList.stream().filter(l -> 3 == l.leasedObject().byteSize()).count()); } @Test @@ -111,9 +125,11 @@ void testTakeZeroLeases() { new UnboundPool<>(new ArenaMemorySegmentLeaseSupplier(Arena.ofShared(), 3), new MemorySegmentLeaseStub()) ); final MultiGet> multiGet = new LeaseMultiGet(pool); - final List> leases = multiGet.get(0); + final OpenableLease[] leases = multiGet.getAsArray(0); + final List> leasesList = multiGet.getAsList(0); - Assertions.assertEquals(0, leases.size()); + Assertions.assertEquals(0, leases.length); + Assertions.assertEquals(0, leasesList.size()); } @Test diff --git a/src/test/java/com/teragrep/buf_01/buffer/TrackedLeaseMultiGetTest.java b/src/test/java/com/teragrep/buf_01/buffer/TrackedLeaseMultiGetTest.java new file mode 100644 index 0000000..c30ccc5 --- /dev/null +++ b/src/test/java/com/teragrep/buf_01/buffer/TrackedLeaseMultiGetTest.java @@ -0,0 +1,97 @@ +/* + * Teragrep Buffer Library for Java + * Copyright (C) 2026 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.buf_01.buffer; + +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.MultiGet; +import com.teragrep.buf_01.buffer.pool.OpeningPool; +import com.teragrep.buf_01.buffer.pool.TrackedLeaseMultiGet; +import com.teragrep.buf_01.buffer.supply.ArenaMemorySegmentLeaseSupplier; +import com.teragrep.poj_01.pool.Pool; +import com.teragrep.poj_01.pool.UnboundPool; +import nl.jqno.equalsverifier.EqualsVerifier; +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.List; + +public final class TrackedLeaseMultiGetTest { + + @Test + void testDecorating() { + final Pool> pool = new OpeningPool( + new UnboundPool<>(new ArenaMemorySegmentLeaseSupplier(Arena.ofShared(), 5), new MemorySegmentLeaseStub()) + ); + final MultiGet> multiGet = new LeaseMultiGet(pool); + final MultiGet> trackedMultiGet = new TrackedLeaseMultiGet(multiGet); + + final TrackedLease[] leases = trackedMultiGet.getAsArray(5); + final List> leasesList = trackedMultiGet.getAsList(5); + + Assertions.assertEquals(1, leases.length); + Assertions.assertEquals(5, leases[0].leasedObject().byteSize()); + Assertions.assertEquals(TrackedMemorySegmentLease.class, leases[0].getClass()); + Assertions.assertEquals(0L, leases[0].currentPosition()); + Assertions.assertEquals(-1L, leases[0].currentLimit()); + + Assertions.assertEquals(1, leasesList.size()); + Assertions.assertEquals(5, leasesList.getFirst().leasedObject().byteSize()); + Assertions.assertEquals(TrackedMemorySegmentLease.class, leasesList.getFirst().getClass()); + Assertions.assertEquals(0L, leasesList.getFirst().currentPosition()); + Assertions.assertEquals(-1L, leasesList.getFirst().currentLimit()); + } + + @Test + void testEqualsContract() { + EqualsVerifier.forClass(TrackedLeaseMultiGet.class).verify(); + } +}