From ef4c48044ff9a0f65b044869434b56c36d5c1297 Mon Sep 17 00:00:00 2001 From: Lee Rhodes Date: Tue, 7 Jan 2025 14:07:26 -0800 Subject: [PATCH 1/6] New Release Branch 5.0.X for Java 21 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c8dc5bbf..29167b34 100644 --- a/pom.xml +++ b/pom.xml @@ -34,7 +34,7 @@ under the License. org.apache.datasketches datasketches-memory - 5.0.0-SNAPSHOT + 5.0.0 jar ${project.artifactId} From d13507b07a9d6803b899ca9e7efe3048b2e113e6 Mon Sep 17 00:00:00 2001 From: Lee Rhodes Date: Thu, 23 Jan 2025 20:47:40 -0800 Subject: [PATCH 2/6] Changes in /main/ tree to accommodate the new FFM API in Java 21. --- .../memory/DefaultMemoryRequestServer.java | 45 +++----------- .../memory/MemoryRequestServer.java | 53 ++++------------ .../apache/datasketches/memory/Resource.java | 37 +----------- .../datasketches/memory/WritableMemory.java | 60 ++++--------------- .../memory/internal/ResourceImpl.java | 17 ------ 5 files changed, 32 insertions(+), 180 deletions(-) diff --git a/src/main/java/org/apache/datasketches/memory/DefaultMemoryRequestServer.java b/src/main/java/org/apache/datasketches/memory/DefaultMemoryRequestServer.java index 0bcbd344..100355d2 100644 --- a/src/main/java/org/apache/datasketches/memory/DefaultMemoryRequestServer.java +++ b/src/main/java/org/apache/datasketches/memory/DefaultMemoryRequestServer.java @@ -24,72 +24,43 @@ /** * This example MemoryRequestServer is simple but demonstrates one of many ways to - * manage continuous requests for larger memory. + * manage continuous requests for larger or smaller memory. * This capability is only available for writable, non-file-memory-mapping resources. * * @author Lee Rhodes */ public final class DefaultMemoryRequestServer implements MemoryRequestServer { - private final boolean offHeap; //create the new memory off-heap; otherwise, on-heap - private final boolean copyOldToNew; //copy data from old memory to new memory. /** * Default constructor. - * Create new memory on-heap and do not copy old contents to new memory. */ public DefaultMemoryRequestServer() { - this(false, false); - } - - /** - * Constructor with parameters - * @param offHeap if true, the returned new memory will be off heap - * @param copyOldToNew if true, the data from the current memory will be copied to the new memory, - * starting at address 0, and through the currentMemory capacity. - */ - public DefaultMemoryRequestServer( - final boolean offHeap, - final boolean copyOldToNew) { - this.offHeap = offHeap; - this.copyOldToNew = copyOldToNew; } @Override public WritableMemory request( - final WritableMemory currentWmem, final long newCapacityBytes, + final long alignmentBytes, + final ByteOrder byteOrder, final Arena arena) { - final ByteOrder order = currentWmem.getTypeByteOrder(); - final long currentBytes = currentWmem.getCapacity(); final WritableMemory newWmem; - if (newCapacityBytes <= currentBytes) { - throw new IllegalArgumentException("newCapacityBytes must be > currentBytes"); - } - - if (offHeap) { - newWmem = WritableMemory.allocateDirect(newCapacityBytes, 8, order, this, arena); + if (arena != null) { + newWmem = WritableMemory.allocateDirect(newCapacityBytes, alignmentBytes, byteOrder, this, arena); } else { //On-heap if (newCapacityBytes > Integer.MAX_VALUE) { throw new IllegalArgumentException("Requested capacity exceeds Integer.MAX_VALUE."); } - newWmem = WritableMemory.allocate((int)newCapacityBytes, order, this); - } - - if (copyOldToNew) { - currentWmem.copyTo(0, newWmem, 0, currentBytes); + newWmem = WritableMemory.allocate((int)newCapacityBytes, byteOrder, this); } return newWmem; } @Override - public void requestClose( - final WritableMemory memToClose, - final WritableMemory newMemory) { - //try to make this operation idempotent. - if (memToClose.isCloseable()) { memToClose.close(); } + public void requestClose(final Arena arena) { + if (arena.scope().isAlive()) { arena.close(); } } } diff --git a/src/main/java/org/apache/datasketches/memory/MemoryRequestServer.java b/src/main/java/org/apache/datasketches/memory/MemoryRequestServer.java index 8a0453a3..648a25a8 100644 --- a/src/main/java/org/apache/datasketches/memory/MemoryRequestServer.java +++ b/src/main/java/org/apache/datasketches/memory/MemoryRequestServer.java @@ -20,9 +20,10 @@ package org.apache.datasketches.memory; import java.lang.foreign.Arena; +import java.nio.ByteOrder; /** - * The MemoryRequestServer is a callback interface to provide a means to request more memory + * The MemoryRequestServer is a callback interface to provide a means to request more or less memory * for heap and off-heap WritableMemory resources that are not file-memory-mapped backed resources. * *

Note: this only works with Java 21. @@ -32,53 +33,25 @@ public interface MemoryRequestServer { /** - * Request new WritableMemory with the given newCapacityBytes. The current WritableMemory can be used to - * determine the byte order of the returned WritableMemory and other properties. A new confined Arena is - * assigned. - * @param currentWritableMemory the current writableMemory of the client. It must be non-null. - * @param newCapacityBytes The capacity being requested. It must be > the capacity of the currentWritableMemory. - * @return new WritableMemory with the requested capacity. - */ - default WritableMemory request( - WritableMemory currentWritableMemory, - long newCapacityBytes) { - - return request(currentWritableMemory, newCapacityBytes, Arena.ofConfined()); - } - - /** - * Request new WritableMemory with the given newCapacityBytes. The current Writable Memory can be used to - * determine the byte order of the returned WritableMemory and other properties. - * @param currentWritableMemory the current writableMemory of the client. It must be non-null. - * @param newCapacityBytes The capacity being requested. It must be > the capacity of the currentWritableMemory. - * @param arena the Arena to be used for the newly allocated memory. It must be non-null. + * Request new WritableMemory with the given newCapacityBytes. + * @param newCapacityBytes The capacity being requested. + * @param alignmentBytes requested segment alignment. Typically 1, 2, 4 or 8. + * @param byteOrder the given ByteOrder. It must be non-null. + * @param arena the given arena to manage the new off-heap WritableMemory. + * If arena is null, the requested WritableMemory will be off-heap. * Warning: This class is not thread-safe. Specifying an Arena that allows multiple threads is not recommended. * @return new WritableMemory with the requested capacity. */ WritableMemory request( - WritableMemory currentWritableMemory, long newCapacityBytes, + long alignmentBytes, + ByteOrder byteOrder, Arena arena); /** - * Request to close the resource, if applicable. - * - * @param memToClose the relevant WritableMemory to be considered for closing. It must be non-null. - */ - default void requestClose(WritableMemory memToClose) { - requestClose(memToClose, null); - } - - /** - * Request to close the resource, if applicable. - * - * @param memToClose the relevant WritableMemory to be considered for closing. It must be non-null. - * @param newMemory the newly allocated WritableMemory. - * The newMemory reference is returned from the client for the convenience of the system that - * owns the responsibility of memory allocation. It may be null. + * Request to close the area managing all the related resources, if applicable. + * @param arena the given arena to use to close all its managed resources. */ - void requestClose( - WritableMemory memToClose, - WritableMemory newMemory); + void requestClose( Arena arena); } diff --git a/src/main/java/org/apache/datasketches/memory/Resource.java b/src/main/java/org/apache/datasketches/memory/Resource.java index 3dcdfefe..3306bcba 100644 --- a/src/main/java/org/apache/datasketches/memory/Resource.java +++ b/src/main/java/org/apache/datasketches/memory/Resource.java @@ -20,8 +20,6 @@ package org.apache.datasketches.memory; import java.lang.foreign.Arena; -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.Linker.Option; import java.lang.foreign.MemorySegment; import java.lang.foreign.MemorySegment.Scope; import java.nio.ByteBuffer; @@ -32,7 +30,7 @@ * * @author Lee Rhodes */ -public interface Resource extends AutoCloseable { +public interface Resource { //MemoryRequestServer logic @@ -92,32 +90,6 @@ public interface Resource extends AutoCloseable { */ ByteBuffer asByteBufferView(ByteOrder order); - /** - * From Java 21 java.lang.foreign.Arena::close(): - * Closes this arena. If this method completes normally, the arena scope is no longer {@linkplain Scope#isAlive() alive}, - * and all the memory segments associated with it can no longer be accessed. Furthermore, any off-heap region of memory backing the - * segments obtained from this arena are also released. - * - *

This operation is not idempotent; that is, closing an already closed arena always results in an - * exception being thrown. This reflects a deliberate design choice: failure to close an arena might reveal a bug - * in the underlying application logic.

- * - *

If this method completes normally, then {@code java.lang.foreign.Arena.scope().isAlive() == false}. - * Implementations are allowed to throw {@link UnsupportedOperationException} if an explicit close operation is - * not supported.

- * - * @see java.lang.foreign.MemorySegment.Scope#isAlive() - * - * @throws IllegalStateException if the arena has already been closed. - * @throws IllegalStateException if a segment associated with this arena is being accessed concurrently, e.g. - * by a {@linkplain java.lang.foreign.Linker#downcallHandle(FunctionDescriptor, Option...) downcall method handle}. - * @throws WrongThreadException if this arena is confined, and this method is called from a thread - * other than the arena's owner thread. - * @throws UnsupportedOperationException if this arena cannot be closed explicitly. - */ - @Override - void close(); - /** * Compares the bytes of this Resource to that Resource. * Returns (this < that) ? (some negative value) : (this > that) ? (some positive value) : 0;. @@ -198,13 +170,6 @@ boolean equalTo( */ boolean hasByteBuffer(); - /** - * Return true if this resource is likely to be closeable, but not guaranteed. - * There is no way to determine if the specific type of Arena is explicitly closeable. - * @return true if this resource is likely to be closeable. - */ - boolean isCloseable(); - /** * Is the underlying resource scope alive? * @return true, if the underlying resource scope is alive. diff --git a/src/main/java/org/apache/datasketches/memory/WritableMemory.java b/src/main/java/org/apache/datasketches/memory/WritableMemory.java index 7395ec61..23d0ba00 100644 --- a/src/main/java/org/apache/datasketches/memory/WritableMemory.java +++ b/src/main/java/org/apache/datasketches/memory/WritableMemory.java @@ -73,40 +73,18 @@ static WritableMemory writableWrap( /** * Maps the entire given file into native-ordered WritableMemory for write operations with Arena.ofConfined(). * Calling this method is equivalent to calling - * {@link #writableMap(File, long, long, ByteOrder) writableMap(file, 0, file.length(), ByteOrder.nativeOrder())}. + * {@link #writableMap(File, long, long, ByteOrder, Arena) writableMap(file, 0, file.length(), ByteOrder.nativeOrder(), arena)}. * @param file the given file to map. It must be non-null and writable. + * @param arena the given arena to manage the new off-heap WritableMemory. It must be non-null. + * Warning: This class is not thread-safe. Specifying an Arena that allows multiple threads is not recommended. * @return a file-mapped WritableMemory * @throws IllegalArgumentException if file is not readable or not writable. * @throws IOException if the specified path does not point to an existing file, or if some other I/O error occurs. * @throws SecurityException If a security manager is installed and it denies an unspecified permission * required by the implementation. */ - static WritableMemory writableMap(File file) throws IOException { - return WritableMemoryImpl.wrapMap(file, 0, file.length(), ByteOrder.nativeOrder(), false, Arena.ofConfined()); - } - - /** - * Maps the specified portion of the given file into Memory for write operations with Arena.ofConfined(). - * Calling this method is equivalent to calling - * {@link #writableMap(File, long, long, ByteOrder, Arena) - * writableMap(file, fileOffsetBytes, capacityBytes, ByteOrder, Arena.ofConfined())}. - * @param file the given file to map. It must be non-null with a non-negative length and writable. - * @param fileOffsetBytes the position in the given file in bytes. It must not be negative. - * @param capacityBytes the size of the mapped Memory. It must be ≥ 0. - * @param byteOrder the byte order to be used. It must be non-null. - * @return mapped WritableMemory. - * @throws IllegalArgumentException -- if file is not readable or writable. - * @throws IllegalArgumentException -- if file is not writable. - * @throws IOException - if the specified path does not point to an existing file, or if some other I/O error occurs. - * @throws SecurityException - If a security manager is installed and it denies an unspecified permission - * required by the implementation. - */ - static WritableMemory writableMap( - File file, - long fileOffsetBytes, - long capacityBytes, - ByteOrder byteOrder) throws IOException { - return WritableMemoryImpl.wrapMap(file, fileOffsetBytes, capacityBytes, byteOrder, false, Arena.ofConfined()); + static WritableMemory writableMap(File file, Arena arena) throws IOException { + return WritableMemoryImpl.wrapMap(file, 0, file.length(), ByteOrder.nativeOrder(), false, arena); } /** @@ -115,8 +93,9 @@ static WritableMemory writableMap( * @param fileOffsetBytes the position in the given file in bytes. It must not be negative. * @param capacityBytes the size of the mapped Memory. * @param byteOrder the given ByteOrder. It must be non-null. - * @param arena the given arena to map. It must be non-null. + * @param arena the given arena to manage the new off-heap WritableMemory. It must be non-null. * Warning: This class is not thread-safe. Specifying an Arena that allows multiple threads is not recommended. + * * @return a file-mapped WritableMemory. * @throws IllegalArgumentException if file is not readable or not writable. * @throws IOException if the specified path does not point to an existing file, or if some other I/O error occurs. @@ -139,34 +118,15 @@ static WritableMemory writableMap( * The allocated memory will be 8-byte aligned. * Native byte order is assumed. * A new DefaultMemoryRequestServer() is created. - * A new Arena.ofConfined() is created. * *

NOTE: Native/Direct memory acquired may have garbage in it. * It is the responsibility of the using application to clear this memory, if required, * and to call close() when done.

* @param capacityBytes the size of the desired memory in bytes. - * Warning: This class is not thread-safe. - * - * @return WritableMemory for this off-heap, native resource. - */ - static WritableMemory allocateDirect(long capacityBytes) { - return allocateDirect(capacityBytes, 8, ByteOrder.nativeOrder(), new DefaultMemoryRequestServer(), Arena.ofConfined()); - } - - /** - * Allocates and provides access to capacityBytes directly in native (off-heap) memory. - * The allocated memory will be 8-byte aligned. - * Native byte order is assumed. - * A new DefaultMemoryRequestServer() is created. - * - *

NOTE: Native/Direct memory acquired may have garbage in it. - * It is the responsibility of the using application to clear this memory, if required, - * and to call close() when done.

- * @param capacityBytes the size of the desired memory in bytes. - * @param arena the given arena to use. It must be non-null. + * @param arena the given arena to manage the new off-heap WritableMemory. It must be non-null. * Warning: This class is not thread-safe. Specifying an Arena that allows multiple threads is not recommended. * - * @return WritableMemory for this off-heap, native resource. + * @return a WritableMemory for this off-heap resource. */ static WritableMemory allocateDirect(long capacityBytes, Arena arena) { return allocateDirect(capacityBytes, 8, ByteOrder.nativeOrder(), new DefaultMemoryRequestServer(), arena); @@ -184,7 +144,7 @@ static WritableMemory allocateDirect(long capacityBytes, Arena arena) { * @param byteOrder the given ByteOrder. It must be non-null. * @param memReqSvr A user-specified MemoryRequestServer, which may be null. * This is a callback mechanism for a user client of direct memory to request more memory. - * @param arena the given arena to use. It must be non-null. + * @param arena the given arena to manage the new off-heap WritableMemory. It must be non-null. * Warning: This class is not thread-safe. Specifying an Arena that allows multiple threads is not recommended. * * @return a WritableMemory for this off-heap resource. diff --git a/src/main/java/org/apache/datasketches/memory/internal/ResourceImpl.java b/src/main/java/org/apache/datasketches/memory/internal/ResourceImpl.java index 3d86ac0b..46e1b187 100644 --- a/src/main/java/org/apache/datasketches/memory/internal/ResourceImpl.java +++ b/src/main/java/org/apache/datasketches/memory/internal/ResourceImpl.java @@ -358,18 +358,6 @@ public final ByteBuffer asByteBufferView(final ByteOrder order) { return byteBuffer; } - @Override - public void close() { - if (arena != null) { - try { - arena.close(); - } - catch (final UnsupportedOperationException uoe) { - // ignored as it seems there's no reliable way to determine if the Arena is closeable or not - } - } //not idempotent - } - @Override public final int compareTo(final long thisOffsetBytes, final long thisLengthBytes, final Resource that, final long thatOffsetBytes, final long thatLengthBytes) { @@ -424,11 +412,6 @@ public final boolean isByteOrderCompatible(final ByteOrder byteOrder) { return typeBO == ByteOrder.nativeOrder() && typeBO == byteOrder; } - @Override - public boolean isCloseable() { - return ((seg.isNative() || seg.isMapped()) && seg.scope().isAlive()); - } - @Override public final boolean isDirect() { assert seg.isNative() == (typeId & DIRECT) > 0; From caa048db9c188e15ebeaa9d7d5fda78a96eb7c27 Mon Sep 17 00:00:00 2001 From: Lee Rhodes Date: Fri, 24 Jan 2025 17:10:42 -0800 Subject: [PATCH 3/6] Minor tweaks to MemoryRequestServer and to Resource. Otherwise everything else is adapting the tests to the new API. --- .../memory/DefaultMemoryRequestServer.java | 3 +- .../apache/datasketches/memory/Resource.java | 17 +++++++-- .../memory/internal/ResourceImpl.java | 37 +++++++++--------- .../internal/AllocateDirectMapMemoryTest.java | 31 ++++++++------- .../internal/AllocateDirectMemoryTest.java | 30 ++++++++------- .../AllocateDirectWritableMapMemoryTest.java | 18 +++++---- .../memory/internal/BufferTest.java | 7 ++-- .../memory/internal/CopyMemoryTest.java | 38 +++++++++---------- .../memory/internal/DruidIssue11544Test.java | 11 ++---- .../ExampleMemoryRequestServerTest.java | 16 ++++---- .../internal/IgnoredArrayOverflowTest.java | 2 +- .../internal/InvalidAllocationTest.java | 6 +-- .../memory/internal/LeafImplTest.java | 2 +- .../internal/MemoryBoundaryCheckTest.java | 7 +--- .../internal/MemoryReadWriteSafetyTest.java | 18 ++++----- .../memory/internal/MemoryTest.java | 4 +- .../NativeWritableBufferImplTest.java | 4 +- .../NativeWritableMemoryImplTest.java | 4 +- .../memory/internal/ResourceTest.java | 28 ++++++++------ 19 files changed, 150 insertions(+), 133 deletions(-) diff --git a/src/main/java/org/apache/datasketches/memory/DefaultMemoryRequestServer.java b/src/main/java/org/apache/datasketches/memory/DefaultMemoryRequestServer.java index 100355d2..d288eee5 100644 --- a/src/main/java/org/apache/datasketches/memory/DefaultMemoryRequestServer.java +++ b/src/main/java/org/apache/datasketches/memory/DefaultMemoryRequestServer.java @@ -34,8 +34,7 @@ public final class DefaultMemoryRequestServer implements MemoryRequestServer { /** * Default constructor. */ - public DefaultMemoryRequestServer() { - } + public DefaultMemoryRequestServer() { } @Override public WritableMemory request( diff --git a/src/main/java/org/apache/datasketches/memory/Resource.java b/src/main/java/org/apache/datasketches/memory/Resource.java index 3306bcba..701b31ec 100644 --- a/src/main/java/org/apache/datasketches/memory/Resource.java +++ b/src/main/java/org/apache/datasketches/memory/Resource.java @@ -142,6 +142,13 @@ boolean equalTo( */ void force(); + /** + * Returns the arena used to create this resource and possibly other resources. + * Be careful when you close the returned Arena, you may be closing other resources as well. + * @return the arena used to create this resource and possibly other resources. + */ + Arena getArena(); + /** * Gets the capacity of this object in bytes * @return the capacity of this object in bytes @@ -311,10 +318,14 @@ boolean equalTo( ByteBuffer toByteBuffer(ByteOrder order); /** - * Returns a copy of the underlying MemorySegment. - * @return a copy of the underlying MemorySegment. + * Returns a copy of the underlying MemorySegment in the given arena. + * @param arena the given arena. + * If the desired result is to be off-heap, the arena must not be null. + * Otherwise, the result will be on-heap. + * @param alignment requested segment alignment. Typically 1, 2, 4 or 8. + * @return a copy of the underlying MemorySegment in the given arena. */ - MemorySegment toMemorySegment(); + MemorySegment toMemorySegment(Arena arena, long alignment); /** * Returns a brief description of this object. diff --git a/src/main/java/org/apache/datasketches/memory/internal/ResourceImpl.java b/src/main/java/org/apache/datasketches/memory/internal/ResourceImpl.java index 46e1b187..1245f65d 100644 --- a/src/main/java/org/apache/datasketches/memory/internal/ResourceImpl.java +++ b/src/main/java/org/apache/datasketches/memory/internal/ResourceImpl.java @@ -93,11 +93,6 @@ abstract class ResourceImpl implements Resource { static final ByteOrder NON_NATIVE_BYTE_ORDER = (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN) ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN; - /** - * The alignment of the starting address of new MemorySegments - */ - static final long SEGMENT_ALIGHMENT = 8; - static { final String jdkVer = System.getProperty("java.version"); final int[] p = parseJavaVersion(jdkVer); @@ -376,6 +371,9 @@ public final boolean equalTo(final long thisOffsetBytes, final Resource that, fi @Override public void force() { seg.force(); } + @Override + public Arena getArena() { return arena; } + @Override public final long getCapacity() { return seg.byteSize(); @@ -546,26 +544,16 @@ public ByteBuffer toByteBuffer(final ByteOrder order) { } @Override - public String toString() { - return toString("", 0, (int)this.getCapacity(), false); - } - - @Override - public final String toString(final String comment, final long offsetBytes, final int lengthBytes, - final boolean withData) { - return toHex(this, comment, offsetBytes, lengthBytes, withData); - } - - @Override - public MemorySegment toMemorySegment() { + public MemorySegment toMemorySegment(final Arena arena, final long alignment) { final long len = seg.byteSize(); + final boolean arenaValid = arena != null; final MemorySegment out; - if (seg.isNative()) { //off-heap + if (arenaValid) { //off-heap if (len == 0) { out = MemorySegment.NULL; return out; } - out = arena.allocate(seg.byteSize(), SEGMENT_ALIGHMENT); + out = arena.allocate(seg.byteSize(), alignment); } else { //on-heap if (len == 0) { @@ -586,6 +574,17 @@ public MemorySegment toMemorySegment() { return out; } + @Override + public String toString() { + return toString("", 0, (int)this.getCapacity(), false); + } + + @Override + public final String toString(final String comment, final long offsetBytes, final int lengthBytes, + final boolean withData) { + return toHex(this, comment, offsetBytes, lengthBytes, withData); + } + @Override public void unload() { seg.unload(); } diff --git a/src/test/java/org/apache/datasketches/memory/internal/AllocateDirectMapMemoryTest.java b/src/test/java/org/apache/datasketches/memory/internal/AllocateDirectMapMemoryTest.java index 5eb162d6..62d38323 100644 --- a/src/test/java/org/apache/datasketches/memory/internal/AllocateDirectMapMemoryTest.java +++ b/src/test/java/org/apache/datasketches/memory/internal/AllocateDirectMapMemoryTest.java @@ -26,6 +26,7 @@ import static org.apache.datasketches.memory.internal.ResourceImpl.LS; import static org.apache.datasketches.memory.internal.Util.getResourceFile; import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; @@ -42,8 +43,9 @@ public class AllocateDirectMapMemoryTest { @Test public void simpleMap() throws IOException { File file = UtilTest.setGettysburgAddressFileToReadOnly(); - try (Memory mem = Memory.map(file, Arena.ofConfined())) { - mem.close(); + try (Arena arena = Arena.ofConfined()) { + Memory mem = Memory.map(file, arena); + arena.close(); } //The Try-With-Resources will throw since it is already closed catch (IllegalStateException e) { /* OK */ } } @@ -51,15 +53,16 @@ public void simpleMap() throws IOException { @Test public void testIllegalArguments() throws IOException { File file = getResourceFile("GettysburgAddress.txt"); - try (Memory mem = Memory.map(file, -1, Integer.MAX_VALUE, ByteOrder.nativeOrder(), Arena.ofConfined())) { + try (Arena arena = Arena.ofConfined()) { + Memory mem = Memory.map(file, -1, Integer.MAX_VALUE, ByteOrder.nativeOrder(), arena); fail("Failed: test IllegalArgumentException: Position was negative."); mem.getCapacity(); } catch (IllegalArgumentException e) { //ok } - try (Arena arena = Arena.ofConfined(); - Memory mem = Memory.map(file, 0, -1, ByteOrder.nativeOrder(), arena)) { + try (Arena arena = Arena.ofConfined()) { + Memory mem = Memory.map(file, 0, -1, ByteOrder.nativeOrder(), arena); fail("Failed: testIllegalArgumentException: Size was negative."); } catch (IllegalArgumentException e) { //ok @@ -72,22 +75,24 @@ public void testMapAndMultipleClose() throws IOException { long memCapacity = file.length(); Memory mem2 = null; try { - try (Memory mem = Memory.map(file, 0, memCapacity, ByteOrder.nativeOrder(), Arena.ofConfined())) { + try (Arena arena = Arena.ofConfined()) { + Memory mem = Memory.map(file, 0, memCapacity, ByteOrder.nativeOrder(), arena); mem2 = mem; assertEquals(memCapacity, mem.getCapacity()); - mem.close(); //a close inside the TWR block will throw - } - } catch (IllegalStateException e) { /* expected */ } - try { - if (mem2 != null) { mem2.close(); } //a close outside the TWR block will throw - } catch (IllegalStateException e) { /* expected */ } + arena.close(); + assertFalse(mem.isAlive()); + } //a close inside the TWR block will throw here + } + catch (IllegalStateException e) { /* expected */ } + assertFalse(mem2.isAlive()); } @Test public void testLoad() throws IOException { File file = getResourceFile("GettysburgAddress.txt"); long memCapacity = file.length(); - try (Memory mem = Memory.map(file, 0, memCapacity, ByteOrder.nativeOrder(), Arena.ofConfined())) { + try (Arena arena = Arena.ofConfined()) { + Memory mem = Memory.map(file, 0, memCapacity, ByteOrder.nativeOrder(), arena); mem.load(); //assertTrue(mem.isLoaded()); //incompatible with Windows assertTrue(mem.isAlive()); diff --git a/src/test/java/org/apache/datasketches/memory/internal/AllocateDirectMemoryTest.java b/src/test/java/org/apache/datasketches/memory/internal/AllocateDirectMemoryTest.java index 3d1fbe47..0a8ebe8e 100644 --- a/src/test/java/org/apache/datasketches/memory/internal/AllocateDirectMemoryTest.java +++ b/src/test/java/org/apache/datasketches/memory/internal/AllocateDirectMemoryTest.java @@ -25,6 +25,7 @@ import static org.testng.Assert.assertTrue; import java.lang.foreign.Arena; +import java.nio.ByteOrder; import org.apache.datasketches.memory.MemoryRequestServer; import org.apache.datasketches.memory.Resource; @@ -39,7 +40,8 @@ public class AllocateDirectMemoryTest { public void simpleAllocateDirect() { int longs = 32; WritableMemory wMem2 = null; - try (WritableMemory wMem = WritableMemory.allocateDirect(longs << 3, Arena.ofConfined())) { + try (Arena arena = Arena.ofConfined()) { + WritableMemory wMem = WritableMemory.allocateDirect(longs << 3, arena); wMem2 = wMem; for (int i = 0; i on-heap + assertTrue(newWmem.isHeap()); + for (int i = 0; i < longs2; i++) { + newWmem.putLong(i << 3, i); + assertEquals(newWmem.getLong(i << 3), i); + } + } //allow the TWR to close all resources } @Test public void checkNonNativeDirect() { MemoryRequestServer myMemReqSvr = Resource.defaultMemReqSvr; - try (WritableMemory wmem = WritableMemory.allocateDirect(128, 8, NON_NATIVE_BYTE_ORDER, myMemReqSvr, Arena.ofConfined())) { + try (Arena arena = Arena.ofConfined()) { + WritableMemory wmem = WritableMemory.allocateDirect(128, 8, NON_NATIVE_BYTE_ORDER, myMemReqSvr, arena); wmem.putChar(0, (char) 1); assertEquals(wmem.getByte(1), (byte) 1); } @@ -90,8 +93,9 @@ public void checkNonNativeDirect() { @Test public void checkExplicitCloseNoTWR() { final long cap = 128; - WritableMemory wmem = WritableMemory.allocateDirect(cap, Arena.ofConfined()); - wmem.close(); //explicit close + Arena arena = Arena.ofConfined(); + WritableMemory wmem = WritableMemory.allocateDirect(cap, arena); + arena.close(); //explicit close } @Test diff --git a/src/test/java/org/apache/datasketches/memory/internal/AllocateDirectWritableMapMemoryTest.java b/src/test/java/org/apache/datasketches/memory/internal/AllocateDirectWritableMapMemoryTest.java index 8e6f3b7d..38e0fc15 100644 --- a/src/test/java/org/apache/datasketches/memory/internal/AllocateDirectWritableMapMemoryTest.java +++ b/src/test/java/org/apache/datasketches/memory/internal/AllocateDirectWritableMapMemoryTest.java @@ -59,8 +59,8 @@ public void setReadOnly() throws IOException { public void simpleMap() throws IllegalArgumentException, InvalidPathException, IllegalStateException, UnsupportedOperationException, IOException, SecurityException { File file = getResourceFile("GettysburgAddress.txt"); - - try (Memory mem = Memory.map(file, Arena.ofConfined())) { + try (Arena arena = Arena.ofConfined()) { + Memory mem = Memory.map(file, arena); byte[] byteArr = new byte[(int)mem.getCapacity()]; mem.getByteArray(0, byteArr, 0, byteArr.length); String text = new String(byteArr, UTF_8); @@ -118,9 +118,11 @@ public void checkNonNativeFile() final long bytes = 8; WritableMemory wmem = null; - wmem = WritableMemory.writableMap(file, 0L, bytes, NON_NATIVE_BYTE_ORDER); + Arena arena = Arena.ofConfined(); + wmem = WritableMemory.writableMap(file, 0L, bytes, NON_NATIVE_BYTE_ORDER, arena); wmem.putChar(0, (char) 1); assertEquals(wmem.getByte(1), (byte) 1); + arena.close(); } @Test @@ -140,8 +142,8 @@ public void simpleMap2() File file = getResourceFile("GettysburgAddress.txt"); assertTrue(file.canRead()); assertFalse(file.canWrite()); - try (Arena arena = Arena.ofConfined(); - WritableMemory wmem = WritableMemory.writableMap(file)) { //assumes file is writable! + try (Arena arena = Arena.ofConfined()) { + WritableMemory wmem = WritableMemory.writableMap(file, arena); //assumes file is writable! It is not. wmem.getCapacity(); } } @@ -151,9 +153,11 @@ public void checkReadException() throws IllegalArgumentException, InvalidPathException, IllegalStateException, UnsupportedOperationException, IOException, SecurityException { File file = getResourceFile("GettysburgAddress.txt"); + Arena arena = Arena.ofConfined(); WritableMemory wmem = null; - wmem = WritableMemory.writableMap(file, 0, 1 << 20, ByteOrder.nativeOrder()); + wmem = WritableMemory.writableMap(file, 0, 1 << 20, ByteOrder.nativeOrder(), arena); //cannot create writableMap from RO file wmem.getCapacity(); + arena.close(); } @Test @@ -180,7 +184,7 @@ public void testForce() String bufStr = new String(buf, UTF_8); assertEquals(bufStr, origStr); - wmem = WritableMemory.writableMap(origFile, 0, correctBytesLen, ByteOrder.nativeOrder()); + wmem = WritableMemory.writableMap(origFile, 0, correctBytesLen, ByteOrder.nativeOrder(), arena); wmem.load(); //assertTrue(wmem.isLoaded()); //incompatible with Windows // over write content diff --git a/src/test/java/org/apache/datasketches/memory/internal/BufferTest.java b/src/test/java/org/apache/datasketches/memory/internal/BufferTest.java index a9f4ae2d..133f5934 100644 --- a/src/test/java/org/apache/datasketches/memory/internal/BufferTest.java +++ b/src/test/java/org/apache/datasketches/memory/internal/BufferTest.java @@ -287,7 +287,7 @@ public void checkParentUseAfterFree() throws Exception { try (Arena arena = Arena.ofConfined()) { WritableMemory wmem = WritableMemory.allocateDirect(bytes, 1, ByteOrder.nativeOrder(), memReqSvr, arena); WritableBuffer wbuf = wmem.asWritableBuffer(); - wmem.close(); + arena.close(); //with -ea assert: Memory not alive. //with -da sometimes segfaults, sometimes passes! wbuf.getLong(); @@ -300,7 +300,7 @@ public void checkRegionUseAfterFree() throws Exception { try (Arena arena = Arena.ofConfined()) { WritableMemory wmem = WritableMemory.allocateDirect(bytes, 1, ByteOrder.nativeOrder(), memReqSvr, arena); Buffer region = wmem.asBuffer().region(); - wmem.close(); + arena.close(); //with -ea assert: Memory not alive. //with -da sometimes segfaults, sometimes passes! region.getByte(); @@ -310,7 +310,8 @@ public void checkRegionUseAfterFree() throws Exception { @Test public void checkCheckNotAliveAfterTWR() { Buffer buf; - try (WritableMemory wmem = WritableMemory.allocateDirect(100, Arena.ofConfined())) { + try (Arena arena = Arena.ofConfined()) { + WritableMemory wmem = WritableMemory.allocateDirect(100, Arena.ofConfined()); buf = wmem.asBuffer(); } try { diff --git a/src/test/java/org/apache/datasketches/memory/internal/CopyMemoryTest.java b/src/test/java/org/apache/datasketches/memory/internal/CopyMemoryTest.java index 9492da0f..5fe681d6 100644 --- a/src/test/java/org/apache/datasketches/memory/internal/CopyMemoryTest.java +++ b/src/test/java/org/apache/datasketches/memory/internal/CopyMemoryTest.java @@ -41,9 +41,9 @@ public class CopyMemoryTest { public void heapWSource() { int k1 = 1 << 20; //longs int k2 = 2 * k1; - WritableMemory srcMem = genMem(k1, false); //!empty + WritableMemory srcMem = genHeapMem(k1, false); //!empty //println(srcMem.toHexString("src: ", 0, k1 << 3)); - WritableMemory dstMem = genMem(k2, true); + WritableMemory dstMem = genHeapMem(k2, true); srcMem.copyTo(0, dstMem, k1 << 3, k1 << 3); //println(dstMem.toHexString("dst: ", 0, k2 << 3)); check(dstMem, k1, k1, 1); @@ -53,8 +53,8 @@ public void heapWSource() { public void heapROSource() { int k1 = 1 << 20; //longs int k2 = 2 * k1; - Memory srcMem = genMem(k1, false); //!empty - WritableMemory dstMem = genMem(k2, true); + Memory srcMem = genHeapMem(k1, false); //!empty + WritableMemory dstMem = genHeapMem(k2, true); srcMem.copyTo(0, dstMem, k1 << 3, k1 << 3); check(dstMem, k1, k1, 1); } @@ -63,32 +63,32 @@ public void heapROSource() { public void directWSource() throws Exception { int k1 = 1 << 20; //longs int k2 = 2 * k1; - WritableMemory srcMem = genWmem(k1, false); - WritableMemory dstMem = genMem(k2, true); + WritableMemory srcMem = genOffHeapMem(k1, false); + WritableMemory dstMem = genHeapMem(k2, true); srcMem.copyTo(0, dstMem, k1 << 3, k1 << 3); check(dstMem, k1, k1, 1); - srcMem.close(); + srcMem.getArena().close(); } @Test public void directROSource() throws Exception { int k1 = 1 << 20; //longs int k2 = 2 * k1; - Memory srcMem = genWmem(k1, false); - WritableMemory dstMem = genMem(k2, true); + Memory srcMem = genOffHeapMem(k1, false); + WritableMemory dstMem = genHeapMem(k2, true); srcMem.copyTo(0, dstMem, k1 << 3, k1 << 3); check(dstMem, k1, k1, 1); - srcMem.close(); + srcMem.getArena().close(); } @Test public void heapWSrcRegion() { int k1 = 1 << 20; //longs //gen baseMem of k1 longs w data - WritableMemory baseMem = genMem(k1, false); //!empty + WritableMemory baseMem = genHeapMem(k1, false); //!empty //gen src region of k1/2 longs, off= k1/2 WritableMemory srcReg = baseMem.writableRegion((k1/2) << 3, (k1/2) << 3); - WritableMemory dstMem = genMem(2 * k1, true); //empty + WritableMemory dstMem = genHeapMem(2 * k1, true); //empty srcReg.copyTo(0, dstMem, k1 << 3, (k1/2) << 3); //println(dstMem.toHexString("dstMem: ", k1 << 3, (k1/2) << 3)); check(dstMem, k1, k1/2, (k1/2) + 1); @@ -98,10 +98,10 @@ public void heapWSrcRegion() { public void heapROSrcRegion() { int k1 = 1 << 20; //longs //gen baseMem of k1 longs w data - WritableMemory baseMem = genMem(k1, false); //!empty + WritableMemory baseMem = genHeapMem(k1, false); //!empty //gen src region of k1/2 longs, off= k1/2 Memory srcReg = baseMem.region((k1/2) << 3, (k1/2) << 3); - WritableMemory dstMem = genMem(2 * k1, true); //empty + WritableMemory dstMem = genHeapMem(2 * k1, true); //empty srcReg.copyTo(0, dstMem, k1 << 3, (k1/2) << 3); check(dstMem, k1, k1/2, (k1/2) + 1); } @@ -110,13 +110,13 @@ public void heapROSrcRegion() { public void directROSrcRegion() throws Exception { int k1 = 1 << 20; //longs //gen baseMem of k1 longs w data, direct - Memory baseMem = genWmem(k1, false); + Memory baseMem = genOffHeapMem(k1, false); //gen src region of k1/2 longs, off= k1/2 Memory srcReg = baseMem.region((k1/2) << 3, (k1/2) << 3); - WritableMemory dstMem = genMem(2 * k1, true); //empty + WritableMemory dstMem = genHeapMem(2 * k1, true); //empty srcReg.copyTo(0, dstMem, k1 << 3, (k1/2) << 3); check(dstMem, k1, k1/2, (k1/2) + 1); - baseMem.close(); + baseMem.getArena().close(); } @Test @@ -150,7 +150,7 @@ private static void check(Memory mem, int offsetLongs, int lengthLongs, int star } } - private static WritableMemory genWmem(int longs, boolean empty) { + private static WritableMemory genOffHeapMem(int longs, boolean empty) { WritableMemory wmem = WritableMemory.allocateDirect(longs << 3, 1, ByteOrder.nativeOrder(), memReqSvr, Arena.ofConfined()); if (empty) { wmem.clear(); @@ -160,7 +160,7 @@ private static WritableMemory genWmem(int longs, boolean empty) { return wmem; } - private static WritableMemory genMem(int longs, boolean empty) { + private static WritableMemory genHeapMem(int longs, boolean empty) { WritableMemory mem = WritableMemory.allocate(longs << 3); if (!empty) { for (int i = 0; i < longs; i++) { mem.putLong(i << 3, i + 1); } diff --git a/src/test/java/org/apache/datasketches/memory/internal/DruidIssue11544Test.java b/src/test/java/org/apache/datasketches/memory/internal/DruidIssue11544Test.java index 9ba9590e..a9e4d631 100644 --- a/src/test/java/org/apache/datasketches/memory/internal/DruidIssue11544Test.java +++ b/src/test/java/org/apache/datasketches/memory/internal/DruidIssue11544Test.java @@ -47,7 +47,7 @@ * */ public class DruidIssue11544Test { - private static final MemoryRequestServer myMemReqSvr = Resource.defaultMemReqSvr; //on heap, no copy + private static final MemoryRequestServer myMemReqSvr = Resource.defaultMemReqSvr; @Test public void withByteBuffer() { @@ -64,7 +64,7 @@ public void withByteBuffer() { //Request Bigger Memory on heap int size2 = size1 * 2; - WritableMemory mem2 = myMemReqSvr.request(mem1, size2); + WritableMemory mem2 = myMemReqSvr.request(size2, 8, ByteOrder.LITTLE_ENDIAN, null); //Confirm that mem2 is on the heap (the default) and 2X size1 assertFalse(mem2.isDirect()); @@ -73,14 +73,12 @@ public void withByteBuffer() { //Move data to new memory mem1.copyTo(0, mem2, 0, size1); - //Request Close - myMemReqSvr.requestClose(mem1, mem2); //ignored, because mem1 is implicit assertTrue(mem1.isAlive()); assertTrue(mem2.isAlive()); //Now we are on the heap and need to grow again: int size3 = size2 * 2; - WritableMemory mem3 = myMemReqSvr.request(mem2, size3); + WritableMemory mem3 = myMemReqSvr.request(size3, 8, ByteOrder.LITTLE_ENDIAN, null); //Confirm that mem3 is still on the heap and 2X of size2 assertFalse(mem3.isDirect()); @@ -89,8 +87,7 @@ public void withByteBuffer() { //Move data to new memory mem2.copyTo(0, mem3, 0, size2); - //Request deallocation - myMemReqSvr.requestClose(mem2, mem3); //ignored, mem2 is on-heap (implicit) + //deallocation via close not relevant, GC does the work. assertTrue(mem2.isAlive()); assertTrue(mem3.isAlive()); } diff --git a/src/test/java/org/apache/datasketches/memory/internal/ExampleMemoryRequestServerTest.java b/src/test/java/org/apache/datasketches/memory/internal/ExampleMemoryRequestServerTest.java index a90a3b1a..55dd7884 100644 --- a/src/test/java/org/apache/datasketches/memory/internal/ExampleMemoryRequestServerTest.java +++ b/src/test/java/org/apache/datasketches/memory/internal/ExampleMemoryRequestServerTest.java @@ -35,6 +35,7 @@ * @author Lee Rhodes */ public class ExampleMemoryRequestServerTest { + private static long alignmentBytes = 8; /** * This version is without a TWR block. All of the memory allocations are done through the MemoryRequestServer @@ -45,11 +46,10 @@ public class ExampleMemoryRequestServerTest { public void checkExampleMemoryRequestServer1() { long workingMemBytes = 8; - long alignmentBytes = 8; Arena arena = Arena.ofConfined(); //Configure the default memReqSvr to create new memory off-heap and copy data from old to new - MemoryRequestServer memReqSvr = new DefaultMemoryRequestServer(true, true); + MemoryRequestServer memReqSvr = new DefaultMemoryRequestServer(); //Create the initial working memory for the client WritableMemory workingMem = WritableMemory.allocateDirect( @@ -65,8 +65,7 @@ public void checkExampleMemoryRequestServer1() { /** * This little client is never happy with how much memory it has been allocated and keeps - * requesting for more. When it does ask for more, the DefaultMemoryRequestServer is configured to copy the old data into the new - * memory. The client must request the MemoryRequestServer to release the prior memory. + * requesting for more. The client must request the MemoryRequestServer to release all the memory at the end. * The client continues working and requesting more memory. * *

In reality, these memory requests should be quite rare.

@@ -95,15 +94,16 @@ void process() { //Not big enough, expand oldWorkingCap = newWorkingCap; newWorkingCap = 2 * oldWorkingCap; - newMem = memReqSvr.request(workingMem, newWorkingCap); //defaults to new confined scope for each iteration + Arena arena = Arena.ofConfined(); // new confined scope for each iteration + newMem = memReqSvr.request(newWorkingCap, alignmentBytes, ByteOrder.LITTLE_ENDIAN, arena); - //done with old memory, close it, if applicable - memReqSvr.requestClose(workingMem, newMem); + //done with old memory, close it + memReqSvr.requestClose(workingMem.getArena()); workingMem = newMem; itr++; } - workingMem.close(); + workingMem.getArena().close(); } } diff --git a/src/test/java/org/apache/datasketches/memory/internal/IgnoredArrayOverflowTest.java b/src/test/java/org/apache/datasketches/memory/internal/IgnoredArrayOverflowTest.java index 4cdb736b..ebd1add4 100644 --- a/src/test/java/org/apache/datasketches/memory/internal/IgnoredArrayOverflowTest.java +++ b/src/test/java/org/apache/datasketches/memory/internal/IgnoredArrayOverflowTest.java @@ -42,7 +42,7 @@ public void allocate() { @AfterClass public void close() throws Exception { - memory.close(); + memory.getArena().close(); } @Test diff --git a/src/test/java/org/apache/datasketches/memory/internal/InvalidAllocationTest.java b/src/test/java/org/apache/datasketches/memory/internal/InvalidAllocationTest.java index f2630cac..8f178604 100644 --- a/src/test/java/org/apache/datasketches/memory/internal/InvalidAllocationTest.java +++ b/src/test/java/org/apache/datasketches/memory/internal/InvalidAllocationTest.java @@ -53,7 +53,7 @@ public void checkInvalidCapacity() throws Exception { Assert.fail(); } catch (IllegalArgumentException ignore) { if (nullMem != null) { - nullMem.close(); + nullMem.getArena().close(); } // expected } @@ -69,12 +69,12 @@ public void checkInvalidAlignment() throws Exception { Memory mem3 = Memory.wrap(ByteBuffer.allocateDirect(0)); mem3.region(0, 0); WritableMemory nullMem = null; - try (Arena arena = Arena.ofConfined()) { //Invalid alignment : 3 + try (Arena arena = Arena.ofConfined()) { //Invalid alignment : 3 nullMem = WritableMemory.allocateDirect(0, 3, ByteOrder.nativeOrder(), memReqSvr, arena); Assert.fail(); } catch (IllegalArgumentException ignore) { if (nullMem != null) { - nullMem.close(); + nullMem.getArena().close(); } // expected } diff --git a/src/test/java/org/apache/datasketches/memory/internal/LeafImplTest.java b/src/test/java/org/apache/datasketches/memory/internal/LeafImplTest.java index bc65914e..799af518 100644 --- a/src/test/java/org/apache/datasketches/memory/internal/LeafImplTest.java +++ b/src/test/java/org/apache/datasketches/memory/internal/LeafImplTest.java @@ -42,7 +42,7 @@ public class LeafImplTest { private static final ByteOrder NBO = ByteOrder.nativeOrder(); private static final ByteOrder NNBO = NON_NATIVE_BYTE_ORDER; - private static final MemoryRequestServer myMemReqSvr = new DefaultMemoryRequestServer(true, true); + private static final MemoryRequestServer myMemReqSvr = new DefaultMemoryRequestServer(); public static ByteOrder otherByteOrder(final ByteOrder order) { return (order == ByteOrder.nativeOrder()) ? NNBO : ByteOrder.nativeOrder(); diff --git a/src/test/java/org/apache/datasketches/memory/internal/MemoryBoundaryCheckTest.java b/src/test/java/org/apache/datasketches/memory/internal/MemoryBoundaryCheckTest.java index 85cb09c4..c29db01e 100644 --- a/src/test/java/org/apache/datasketches/memory/internal/MemoryBoundaryCheckTest.java +++ b/src/test/java/org/apache/datasketches/memory/internal/MemoryBoundaryCheckTest.java @@ -34,12 +34,7 @@ public class MemoryBoundaryCheckTest { @BeforeClass public void allocate() { - writableBuffer = WritableMemory.allocate(8).asWritableBuffer(); - } - - @AfterClass - public void close() throws Exception { - writableBuffer.close(); + writableBuffer = WritableMemory.allocate(8).asWritableBuffer(); //on heap } @Test diff --git a/src/test/java/org/apache/datasketches/memory/internal/MemoryReadWriteSafetyTest.java b/src/test/java/org/apache/datasketches/memory/internal/MemoryReadWriteSafetyTest.java index db9021ed..25a54eb1 100644 --- a/src/test/java/org/apache/datasketches/memory/internal/MemoryReadWriteSafetyTest.java +++ b/src/test/java/org/apache/datasketches/memory/internal/MemoryReadWriteSafetyTest.java @@ -41,13 +41,13 @@ public class MemoryReadWriteSafetyTest { @BeforeClass public void allocate() { - mem = (WritableMemory) Memory.wrap(new byte[8]); + mem = (WritableMemory) Memory.wrap(new byte[8]); //on heap } - @AfterClass - public void close() throws Exception { - mem.close(); - } +// @AfterClass +// public void close() throws Exception { +// mem.close(); +// } @Test(expectedExceptions = UnsupportedOperationException.class) public void testPutByte() { @@ -187,7 +187,6 @@ public void testByteBufferWrap() { mem1.putInt(0, 1); } - //@SuppressWarnings("resource") @Test(expectedExceptions = UnsupportedOperationException.class) public void testMapFile() throws Exception { File tempFile = File.createTempFile("test", null); @@ -195,10 +194,9 @@ public void testMapFile() throws Exception { try (RandomAccessFile raf = new RandomAccessFile(tempFile, "rw")) { raf.setLength(8); //System.out.println(UtilTest.getFileAttributes(tempFile)); - try (Arena arena = Arena.ofConfined(); - Memory memory = Memory.map(tempFile, arena)) { - - ((WritableMemory) memory).putInt(0, 1); + try (Arena arena = Arena.ofConfined()) { + Memory memory = Memory.map(tempFile, arena); + ((WritableMemory) memory).putInt(0, 1); //cannot write into read only resource } } } diff --git a/src/test/java/org/apache/datasketches/memory/internal/MemoryTest.java b/src/test/java/org/apache/datasketches/memory/internal/MemoryTest.java index 84518398..86f8fa68 100644 --- a/src/test/java/org/apache/datasketches/memory/internal/MemoryTest.java +++ b/src/test/java/org/apache/datasketches/memory/internal/MemoryTest.java @@ -356,7 +356,7 @@ public void checkParentUseAfterFree() throws Exception { int bytes = 64 * 8; try (Arena arena = Arena.ofConfined()) { WritableMemory wmem = WritableMemory.allocateDirect(bytes, 1, ByteOrder.nativeOrder(), myMemReqSvr, arena); - wmem.close(); + wmem.getArena().close(); wmem.getLong(0); //Already closed } } @@ -367,7 +367,7 @@ public void checkRegionUseAfterFree() throws Exception { try (Arena arena = Arena.ofConfined()) { WritableMemory wmem = WritableMemory.allocateDirect(bytes, 1, ByteOrder.nativeOrder(), myMemReqSvr, arena); Memory region = wmem.region(0L, bytes); - wmem.close(); + wmem.getArena().close(); region.getByte(0); //Already closed. } } diff --git a/src/test/java/org/apache/datasketches/memory/internal/NativeWritableBufferImplTest.java b/src/test/java/org/apache/datasketches/memory/internal/NativeWritableBufferImplTest.java index bd642d92..1a0a29f3 100644 --- a/src/test/java/org/apache/datasketches/memory/internal/NativeWritableBufferImplTest.java +++ b/src/test/java/org/apache/datasketches/memory/internal/NativeWritableBufferImplTest.java @@ -50,9 +50,9 @@ public void checkNativeCapacityAndClose() throws Exception { WritableBuffer wbuf = wmem.asWritableBuffer(); assertEquals(wbuf.getCapacity(), memCapacity); - wmem.close(); + wmem.getArena().close(); assertFalse(wbuf.isAlive()); - try { wmem.close(); } catch (IllegalStateException e) { } + try { wmem.getArena().close(); } catch (IllegalStateException e) { } } //Simple Heap arrays diff --git a/src/test/java/org/apache/datasketches/memory/internal/NativeWritableMemoryImplTest.java b/src/test/java/org/apache/datasketches/memory/internal/NativeWritableMemoryImplTest.java index ce3266ef..7a410b74 100644 --- a/src/test/java/org/apache/datasketches/memory/internal/NativeWritableMemoryImplTest.java +++ b/src/test/java/org/apache/datasketches/memory/internal/NativeWritableMemoryImplTest.java @@ -53,9 +53,9 @@ public void checkNativeCapacityAndClose() throws Exception { Arena.ofConfined()); assertEquals(memCapacity, wmem.getCapacity()); - wmem.close(); + wmem.getArena().close(); assertFalse(wmem.isAlive()); - try { wmem.close(); } catch (IllegalStateException e) { } + try { wmem.getArena().close(); } catch (IllegalStateException e) { } } //Simple Native arrays diff --git a/src/test/java/org/apache/datasketches/memory/internal/ResourceTest.java b/src/test/java/org/apache/datasketches/memory/internal/ResourceTest.java index c9acfee9..c4fceba0 100644 --- a/src/test/java/org/apache/datasketches/memory/internal/ResourceTest.java +++ b/src/test/java/org/apache/datasketches/memory/internal/ResourceTest.java @@ -123,10 +123,12 @@ public void checkCompareToSamePrefix() { @Test public void checkGetRelativeOffset() { - WritableMemory wmem = WritableMemory.allocateDirect(1024); - WritableMemory reg = wmem.writableRegion(512, 256); - long off = wmem.getRelativeOffset(reg); - assertEquals(off, 512); + try (Arena arena = Arena.ofConfined()) { + WritableMemory wmem = WritableMemory.allocateDirect(1024, arena); + WritableMemory reg = wmem.writableRegion(512, 256); + long off = wmem.getRelativeOffset(reg); + assertEquals(off, 512); + } } @Test @@ -137,9 +139,11 @@ public void checkIsByteOrderCompatible() { @Test public void checkIsSameResource() { - WritableMemory wmem = WritableMemory.allocateDirect(1024); - WritableMemory reg = wmem.writableRegion(0, 1024); - assertTrue(wmem.isSameResource(reg)); + try (Arena arena = Arena.ofConfined()) { + WritableMemory wmem = WritableMemory.allocateDirect(1024, arena); + WritableMemory reg = wmem.writableRegion(0, 1024); + assertTrue(wmem.isSameResource(reg)); + } } @Test @@ -222,31 +226,31 @@ public void checkToMemorySegment() { { int len = 0; WritableMemory mem = WritableMemory.allocate(len); - MemorySegment seg = mem.toMemorySegment(); + MemorySegment seg = mem.toMemorySegment(null, 8); assertEquals(seg.byteSize(), len); } { int len = 13 * 8; WritableMemory mem = WritableMemory.allocate(len); - MemorySegment seg = mem.toMemorySegment(); + MemorySegment seg = mem.toMemorySegment(null, 8); assertEquals(seg.byteSize(), len); } { int len = 13 * 4; WritableMemory mem = WritableMemory.allocate(len); - MemorySegment seg = mem.toMemorySegment(); + MemorySegment seg = mem.toMemorySegment(null, 8); assertEquals(seg.byteSize(), len); } { int len = 13 * 2; WritableMemory mem = WritableMemory.allocate(len); - MemorySegment seg = mem.toMemorySegment(); + MemorySegment seg = mem.toMemorySegment(null, 8); assertEquals(seg.byteSize(), len); } { int len = 13; WritableMemory mem = WritableMemory.allocate(len); - MemorySegment seg = mem.toMemorySegment(); + MemorySegment seg = mem.toMemorySegment(null, 8); assertEquals(seg.byteSize(), len); } } From 083b5e45a1ec5c19131b8cc66861ea131e3b93d6 Mon Sep 17 00:00:00 2001 From: Lee Rhodes Date: Fri, 24 Jan 2025 17:11:18 -0800 Subject: [PATCH 4/6] Missed this one ... --- .../java/org/apache/datasketches/memory/MemoryRequestServer.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/apache/datasketches/memory/MemoryRequestServer.java b/src/main/java/org/apache/datasketches/memory/MemoryRequestServer.java index 648a25a8..a5eab400 100644 --- a/src/main/java/org/apache/datasketches/memory/MemoryRequestServer.java +++ b/src/main/java/org/apache/datasketches/memory/MemoryRequestServer.java @@ -50,6 +50,7 @@ WritableMemory request( /** * Request to close the area managing all the related resources, if applicable. + * Be careful when you request to close the given Arena, you may be closing other resources as well. * @param arena the given arena to use to close all its managed resources. */ void requestClose( Arena arena); From 47107b1daa38e3537a36080a3b9d2b230c1d53f1 Mon Sep 17 00:00:00 2001 From: Lee Rhodes Date: Fri, 24 Jan 2025 17:23:59 -0800 Subject: [PATCH 5/6] Update javadoc and add 2 suppressWarnings --- .../datasketches/memory/internal/WritableMemoryImpl.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/apache/datasketches/memory/internal/WritableMemoryImpl.java b/src/main/java/org/apache/datasketches/memory/internal/WritableMemoryImpl.java index 953e8e8e..a3299115 100644 --- a/src/main/java/org/apache/datasketches/memory/internal/WritableMemoryImpl.java +++ b/src/main/java/org/apache/datasketches/memory/internal/WritableMemoryImpl.java @@ -138,18 +138,16 @@ public static WritableMemory wrapByteBuffer( * This method is also used for read-only operations when localReadOnly is false. * @param file the given file to map. It must be non-null. * @param fileOffsetBytes the file starting offset in bytes. It must be ≥ 0. - * @param capacityBytes the capacity of the mapped memory. It must be ≥ 0. - * It must be non-null. - * Typically use Arena.ofConfined(). - * Warning: This class is not thread-safe. Specifying an Arena that allows multiple threads is not recommended. + * @param capacityBytes the capacity of the mapped memory. It must be ≥ 0. It must be non-null. * @param byteOrder the given ByteOrder. It must be non-null. * @param localReadOnly true if read-only is being imposed locally, even if the given file is writable.. - * @param arena the given arena. It must be non-null. + * @param arena the given arena. It must be non-null. Typically use Arena.ofConfined(). * Warning: This class is not thread-safe. Specifying an Arena that allows multiple threads is not recommended. * @return a WritableMemory * @throws IllegalArgumentException if file is not readable. * @throws IOException if mapping is not successful. */ + @SuppressWarnings("resource") public static WritableMemory wrapMap( final File file, final long fileOffsetBytes, @@ -204,6 +202,7 @@ public static WritableMemory wrapMap( * Warning: This class is not thread-safe. Specifying an Arena that allows multiple threads is not recommended. * @return WritableMemory */ + @SuppressWarnings("resource") public static WritableMemory wrapDirect( final long capacityBytes, final long alignmentBytes, From c354c48e299d0ba30df972fddd0b9f4a59fdd3d9 Mon Sep 17 00:00:00 2001 From: Lee Rhodes Date: Mon, 27 Jan 2025 16:09:49 -0800 Subject: [PATCH 6/6] Change pom version to 5.1.0-SNAPSHOT --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 29167b34..ab4016d8 100644 --- a/pom.xml +++ b/pom.xml @@ -34,7 +34,7 @@ under the License. org.apache.datasketches datasketches-memory - 5.0.0 + 5.1.0-SNAPSHOT jar ${project.artifactId}