This is an automated email from the ASF dual-hosted git repository. leerho pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/datasketches-memory17.git
commit 742b581ce0fc0989e3e3aa53a34f6c1905bf18a9 Author: Lee Rhodes <[email protected]> AuthorDate: Thu Sep 28 10:14:58 2023 -0700 Wrap ResourceScope in MemoryScope. --- pom.xml | 6 +- .../org/apache/datasketches/memory/BaseState.java | 12 +- .../org/apache/datasketches/memory/Memory.java | 15 +- .../apache/datasketches/memory/MemoryScope.java | 135 +++++++----------- .../apache/datasketches/memory/WritableMemory.java | 31 ++-- .../memory/internal/BaseStateImpl.java | 9 +- .../memory/internal/BaseWritableBufferImpl.java | 9 ++ .../memory/internal/BaseWritableMemoryImpl.java | 75 +++++++--- .../memory/internal/MemoryScopeImpl.java | 157 +++++++++++++++++++++ .../memory/internal/NativeWritableBufferImpl.java | 2 +- .../memory/internal/NativeWritableMemoryImpl.java | 2 +- .../internal/NonNativeWritableBufferImpl.java | 2 +- .../internal/NonNativeWritableMemoryImpl.java | 2 +- 13 files changed, 317 insertions(+), 140 deletions(-) diff --git a/pom.xml b/pom.xml index c133dbf..84cd565 100644 --- a/pom.xml +++ b/pom.xml @@ -99,8 +99,10 @@ under the License. <!-- END:UNIQUE FOR THIS JAVA COMPONENT --> <!-- Test --> - <!-- Version 7.4.0 fails to locate jquery.min.js for reporting on debian systems --> - <testng.version>7.5</testng.version> + <!-- Version 7.4.0 fails to locate jquery.min.js for reporting on debian systems. + Version 7.5 has a serious security bug, for Java 8 use 7.5.1. + For Java 9+ use 7.8+ --> + <testng.version>7.5.1</testng.version> <!-- System-wide properties --> <maven.version>3.5.0</maven.version> diff --git a/src/main/java/org/apache/datasketches/memory/BaseState.java b/src/main/java/org/apache/datasketches/memory/BaseState.java index 7bfbab8..e19064c 100644 --- a/src/main/java/org/apache/datasketches/memory/BaseState.java +++ b/src/main/java/org/apache/datasketches/memory/BaseState.java @@ -23,7 +23,6 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; import jdk.incubator.foreign.MemorySegment; -import jdk.incubator.foreign.ResourceScope; /** * Keeps key configuration state for Memory and Buffer plus some common static variables @@ -38,10 +37,13 @@ public interface BaseState { */ static final String LS = System.getProperty("line.separator"); + /** Constant native ByteOrder */ static final ByteOrder NATIVE_BYTE_ORDER = ByteOrder.nativeOrder(); + /** Constant non-native ByteOrder */ static final ByteOrder NON_NATIVE_BYTE_ORDER = ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN; + /** Constant default MemoryRequestServer */ static final MemoryRequestServer defaultMemReqSvr = new DefaultMemoryRequestServer(); /** @@ -203,16 +205,16 @@ public interface BaseState { boolean isSameResource(Object that); /** - * Loads the contents of this mapped segment into physical memory. Please refer to + * Loads the contents of this mapped memory instance into physical memory. Please refer to * <a href="https://docs.oracle.com/en/java/javase/17/docs/api/jdk.incubator.foreign/jdk/incubator/foreign/MemorySegment.html#load()">load()</a> */ void load(); /** - * Returns the resource scope associated with this memory segment. - * @return the resource scope associated with this memory segment. + * Returns the MemoryScope associated with this memory instance. + * @return the MemoryScope associated with this memory instance. */ - ResourceScope scope(); + MemoryScope scope(); // /** // * Sets the default MemoryRequestServer to be used in case of capacity overflow of off-heap diff --git a/src/main/java/org/apache/datasketches/memory/Memory.java b/src/main/java/org/apache/datasketches/memory/Memory.java index 1c9e5e2..778d69a 100644 --- a/src/main/java/org/apache/datasketches/memory/Memory.java +++ b/src/main/java/org/apache/datasketches/memory/Memory.java @@ -28,7 +28,6 @@ import java.nio.ByteOrder; import org.apache.datasketches.memory.internal.BaseWritableMemoryImpl; import jdk.incubator.foreign.MemorySegment; -import jdk.incubator.foreign.ResourceScope; /** * Defines the read-only API for offset access to a resource. @@ -71,10 +70,10 @@ public interface Memory extends BaseState { /** * Maps the given file into <i>Memory</i> for read operations * Calling this method is equivalent to calling - * {@link #map(File, long, long, ResourceScope, ByteOrder) + * {@link #map(File, long, long, MemoryScope, ByteOrder) * map(file, 0, file.length(), scope, ByteOrder.nativeOrder())}. * @param file the given file to map. It must be non-null with a non-negative length and readable. - * @param scope the given ResourceScope. It must be non-null. + * @param memScope the given MemoryScope. It must be non-null. * @return mapped Memory. * @throws IllegalArgumentException -- if file is not readable. * @throws IllegalStateException - if scope has been already closed, or if access occurs from a thread other @@ -83,9 +82,9 @@ public interface Memory extends BaseState { * @throws SecurityException - If a security manager is installed and it denies an unspecified permission * required by the implementation. */ - static Memory map(File file, ResourceScope scope) + static Memory map(File file, MemoryScope memScope) throws IllegalArgumentException, IllegalStateException, IOException, SecurityException { - return map(file, 0, file.length(), scope, ByteOrder.nativeOrder()); + return map(file, 0, file.length(), memScope, ByteOrder.nativeOrder()); } /** @@ -93,7 +92,7 @@ public interface Memory extends BaseState { * @param file the given file to map. It must be non-null,readable and length ≥ 0. * @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 not be negative.. - * @param scope the given ResourceScope. It must be non-null. + * @param memScope the given MemoryScope. It must be non-null. * @param byteOrder the byte order to be used. It must be non-null. * @return mapped Memory * @throws IllegalArgumentException -- if file is not readable. @@ -103,9 +102,9 @@ public interface Memory extends BaseState { * @throws SecurityException - If a security manager is installed and it denies an unspecified permission * required by the implementation. */ - static Memory map(File file, long fileOffsetBytes, long capacityBytes, ResourceScope scope, ByteOrder byteOrder) + static Memory map(File file, long fileOffsetBytes, long capacityBytes, MemoryScope memScope, ByteOrder byteOrder) throws IllegalArgumentException, IllegalStateException, IOException, SecurityException { - return BaseWritableMemoryImpl.wrapMap(file, fileOffsetBytes, capacityBytes, scope, true, byteOrder); + return BaseWritableMemoryImpl.wrapMap(file, fileOffsetBytes, capacityBytes, memScope, true, byteOrder); } //NO ALLOCATE DIRECT, makes no sense diff --git a/src/main/java/org/apache/datasketches/memory/MemoryScope.java b/src/main/java/org/apache/datasketches/memory/MemoryScope.java index fe18a9c..053c344 100644 --- a/src/main/java/org/apache/datasketches/memory/MemoryScope.java +++ b/src/main/java/org/apache/datasketches/memory/MemoryScope.java @@ -21,142 +21,113 @@ package org.apache.datasketches.memory; import java.lang.ref.Cleaner; -import jdk.incubator.foreign.ResourceScope; +import org.apache.datasketches.memory.internal.MemoryScopeImpl; + /** * A wrapper around jdk.incubator.foreign.ResourceScope */ -@SuppressWarnings("resource") -public final class MemoryScope { - private ResourceScope resourceScope; - - private MemoryScope(final ResourceScope resourceScope) { - this.resourceScope = resourceScope; - } - - /** - * Acquires a <i>MemoryScope.Handle</i> associated with this <i>MemoryScope</i>. - * The underlying explicit <i>ResourceScope</i> cannot be closed until all the scope handles - * acquired from it have been <i>release(Handle)</i> released. - * @return a <i>MemoryScope.Handle</i>. - */ - public Handle acquire() { - return new Handle(); - } +public abstract class MemoryScope { /** - * Add a custom cleanup action which will be executed when the underlying <i>ResourceScope</i> is closed. - * The order in which custom cleanup actions are invoked once the scope is closed is unspecified. - * - * @param runnable the custom cleanup action to be associated with this scope. - * @throws IllegalStateException if this scope has already been closed. + * @return a new <i>MemoryScope</i> that wraps a <i>ResourceScope.globalScope()</i>. */ - public void addCloseAction(final Runnable runnable) { - resourceScope.addCloseAction(runnable); + public static MemoryScope globalScope() { + return MemoryScopeImpl.getGlobalScope(); } /** - * Closes this the underlying <i>ResourceScope</i>. + * @return a new <i>MemoryScope</i> that wraps a <i>ResourceScope.newConfiledScope()</i>. */ - public void close() { - if (resourceScope != null) { - resourceScope.close(); - } + public static MemoryScope newConfinedScope() { + return MemoryScopeImpl.getNewConfinedScope(); } /** - * Returns the underlying <i>ResourceScope</i>. - * @return the underlying <i>ResourceScope</i>. + * @param cleaner a user defined <i>Cleaner</i> for this scope + * @return a new <i>MemoryScope</i> that wraps a <i>ResourceScope.newConfinedScope(Cleaner)</i>. */ - ResourceScope getResourceScope() { - return resourceScope; + public static MemoryScope newConfinedScope(final Cleaner cleaner) { + return MemoryScopeImpl.getNewConfinedScope(cleaner); } /** - * @return a new <i>MemoryScope</i> that wraps a <i>ResourceScope.globalScope()</i>. + * @return a new <i>MemoryScope</i> that wraps a <i>ResourceScope.newSharedScope()</i>. */ - public static MemoryScope globalScope() { - return new MemoryScope(ResourceScope.globalScope()); + public static MemoryScope newSharedScope() { + return MemoryScopeImpl.getNewSharedScope(); } /** - * Is the underlying <i>ResourceScope</i> alive? - * @return true if this resource scope is alive. + * @param cleaner a user defined <i>Cleaner</i> for this scope + * @return a new <i>MemoryScope</i> that wraps a <i>ResourceScope.newSharedScope(Cleaner)</i>. */ - public boolean isAlive() { - return resourceScope.isAlive(); + public static MemoryScope newSharedScope(final Cleaner cleaner) { + return MemoryScopeImpl.getNewSharedScope(cleaner); } /** - * Is the underlying <i>ResourceScope</i> alive? - * @return true if the underlying <i>ResourceScope</i> is alive. + * Acquires a <i>MemoryScope.Handle</i> associated with this <i>MemoryScope</i>. + * The underlying explicit <i>ResourceScope</i> cannot be closed until all the scope handles + * acquired from it have been <i>release(Handle)</i> released. + * @return a <i>MemoryScope.Handle</i>. */ - public boolean isImplicit() { - return resourceScope.isImplicit(); - } + public abstract Handle acquire(); /** - * @return a new <i>MemoryScope</i> that wraps a <i>ResourceScope.newConfiledScope()</i>. + * Add a custom cleanup action which will be executed when the underlying <i>ResourceScope</i> is closed. + * The order in which custom cleanup actions are invoked once the scope is closed is unspecified. + * + * @param runnable the custom cleanup action to be associated with this scope. + * @throws IllegalStateException if this scope has already been closed. */ - public static MemoryScope newConfinedScope() { - return new MemoryScope(ResourceScope.newConfinedScope()); - } + public abstract void addCloseAction(final Runnable runnable); /** - * @param cleaner a user defined <i>Cleaner</i> for this scope - * @return a new <i>MemoryScope</i> that wraps a <i>ResourceScope.newConfinedScope(Cleaner)</i>. + * Closes this the underlying <i>ResourceScope</i>. */ - public static MemoryScope newConfinedScope(final Cleaner cleaner) { - return new MemoryScope(ResourceScope.newConfinedScope(cleaner)); - } + public abstract void close(); /** - * @return a new <i>MemoryScope</i> that wraps a <i>ResourceScope.newSharedScope()</i>. + * Is the underlying <i>ResourceScope</i> alive? + * @return true if this resource scope is alive. */ - public static MemoryScope newSharedScope() { - return new MemoryScope(ResourceScope.newSharedScope()); - } + public abstract boolean isAlive(); /** - * @param cleaner a user defined <i>Cleaner</i> for this scope - * @return a new <i>MemoryScope</i> that wraps a <i>ResourceScope.newSharedScope(Cleaner)</i>. + * Is the underlying <i>ResourceScope</i> alive? + * @return true if the underlying <i>ResourceScope</i> is alive. */ - public static MemoryScope newSharedScope(final Cleaner cleaner) { - return new MemoryScope(ResourceScope.newSharedScope(cleaner)); - } + public abstract boolean isImplicit(); /** * The thread owning the underlying <i>ResourceScope</i>. * @return the thread owning the underlying <i>ResourceScope</i>. */ - public Thread ownerThread() { - return resourceScope.ownerThread(); - } + public abstract Thread ownerThread(); - public void release(final MemoryScope.Handle handle) { - if (handle.scope() == this) { handle.release(handle); } - } + /** + * Releases the given handle + * @param handle the given handle + */ + public abstract void release(final MemoryScope.Handle handle); /** * A handle for this <i>MemoryScope</i>. */ - public class Handle { - private ResourceScope.Handle myResourceHandle; - - Handle() { - this.myResourceHandle = resourceScope.acquire(); - } + public abstract class Handle { /** * Returns the <i>MemoryScope</i> associated with this handle. * @return the <i>MemoryScope</i> associated with this handle. */ - public MemoryScope scope() { return MemoryScope.this; } + public abstract MemoryScope scope(); + + /** + * Releases the given handle if valid. + * @param handle the given handle + */ + public abstract void release(final MemoryScope.Handle handle); - void release(final MemoryScope.Handle handle) { - if (handle.myResourceHandle == myResourceHandle) { - MemoryScope.this.resourceScope.release(myResourceHandle); - } - } } } diff --git a/src/main/java/org/apache/datasketches/memory/WritableMemory.java b/src/main/java/org/apache/datasketches/memory/WritableMemory.java index d3e6247..d2a6d7a 100644 --- a/src/main/java/org/apache/datasketches/memory/WritableMemory.java +++ b/src/main/java/org/apache/datasketches/memory/WritableMemory.java @@ -27,7 +27,6 @@ import java.nio.ByteOrder; import org.apache.datasketches.memory.internal.BaseWritableMemoryImpl; import jdk.incubator.foreign.MemorySegment; -import jdk.incubator.foreign.ResourceScope; /** * Defines the writable API for offset access to a resource. @@ -71,10 +70,10 @@ public interface WritableMemory extends Memory { /** * Maps the entire given file into native-ordered WritableMemory for write operations * Calling this method is equivalent to calling - * {@link #writableMap(File, long, long, ResourceScope, ByteOrder) + * {@link #writableMap(File, long, long, MemoryScope, ByteOrder) * writableMap(file, 0, file.length(), scope, ByteOrder.nativeOrder())}. * @param file the given file to map. It must be non-null with a non-negative length and writable. - * @param scope the give Resource Scope. It must be non-null. + * @param memScope the given MemoryScope. It must be non-null. * @return mapped WritableMemory * @throws IllegalArgumentException -- if file is not readable. * @throws IllegalArgumentException -- if file is not writable. @@ -84,9 +83,9 @@ public interface WritableMemory extends Memory { * @throws SecurityException - If a security manager is installed and it denies an unspecified permission * required by the implementation. */ - static WritableMemory writableMap(File file, ResourceScope scope) + static WritableMemory writableMap(File file, MemoryScope memScope) throws IllegalArgumentException, IllegalStateException, IOException, SecurityException { - return writableMap(file, 0, file.length(), scope, ByteOrder.nativeOrder()); + return writableMap(file, 0, file.length(), memScope, ByteOrder.nativeOrder()); } /** @@ -94,7 +93,7 @@ public interface WritableMemory extends Memory { * @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 scope the give Resource Scope. It must be non-null. + * @param memScope the given MemoryScope. It must be non-null. * @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. @@ -105,9 +104,9 @@ public interface WritableMemory extends Memory { * @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, ResourceScope scope, + static WritableMemory writableMap(File file, long fileOffsetBytes, long capacityBytes, MemoryScope memScope, ByteOrder byteOrder) throws IllegalArgumentException, IllegalStateException, IOException, SecurityException { - return BaseWritableMemoryImpl.wrapMap(file, fileOffsetBytes, capacityBytes, scope, false, byteOrder); + return BaseWritableMemoryImpl.wrapMap(file, fileOffsetBytes, capacityBytes, memScope, false, byteOrder); } //ALLOCATE DIRECT @@ -120,12 +119,13 @@ public interface WritableMemory extends Memory { * <p><b>NOTICE:</b> It is the responsibility of the using application to call <i>close()</i> when done.</p> * * @param capacityBytes the size of the desired memory in bytes. - * @param scope the given ResourceScope. It must be non-null. + * @param memScope the given MemoryScope. It must be non-null. * @param memReqSvr A user-specified MemoryRequestServer, which may be null. * @return WritableMemory for this off-heap, native resource. */ - static WritableMemory allocateDirect(long capacityBytes, ResourceScope scope, MemoryRequestServer memReqSvr) { - return allocateDirect(capacityBytes, 8, scope, ByteOrder.nativeOrder(), memReqSvr); + static WritableMemory allocateDirect(long capacityBytes, MemoryScope memScope, MemoryRequestServer memReqSvr) { + return allocateDirect(capacityBytes, 8, memScope, + ByteOrder.nativeOrder(), memReqSvr); } /** @@ -137,7 +137,7 @@ public interface WritableMemory extends Memory { * * @param capacityBytes the size of the desired memory in bytes. * @param alignmentBytes requested segment alignment. Typically 1, 2, 4 or 8. - * @param scope the given ResourceScope. It must be non-null. + * @param memScope the given MemoryScope. It must be non-null. * @param byteOrder the byte order to be used. 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. @@ -146,10 +146,11 @@ public interface WritableMemory extends Memory { static WritableMemory allocateDirect( long capacityBytes, long alignmentBytes, - ResourceScope scope, + MemoryScope memScope, ByteOrder byteOrder, MemoryRequestServer memReqSvr) { - return BaseWritableMemoryImpl.wrapDirect(capacityBytes, alignmentBytes, scope, byteOrder, memReqSvr); + return BaseWritableMemoryImpl.wrapDirect(capacityBytes, alignmentBytes, + memScope, byteOrder, memReqSvr); } //REGIONS @@ -547,7 +548,7 @@ public interface WritableMemory extends Memory { * Gets the MemoryRequestServer implementation, if set, to request additional memory. * The user must customize the actions of the MemoryRequestServer by * implementing the MemoryRequestServer interface and set using this method: - * {@link WritableMemory#allocateDirect(long, long, ResourceScope, ByteOrder, MemoryRequestServer)}. + * {@link WritableMemory#allocateDirect(long, long, MemoryScope, ByteOrder, MemoryRequestServer)}. * Simple implementation examples include the DefaultMemoryRequestServer in the main tree, as well as * the ExampleMemoryRequestServerTest and the use with ByteBuffer documented in the DruidIssue11544Test * in the test tree. diff --git a/src/main/java/org/apache/datasketches/memory/internal/BaseStateImpl.java b/src/main/java/org/apache/datasketches/memory/internal/BaseStateImpl.java index 7167a27..bc0e603 100644 --- a/src/main/java/org/apache/datasketches/memory/internal/BaseStateImpl.java +++ b/src/main/java/org/apache/datasketches/memory/internal/BaseStateImpl.java @@ -27,12 +27,12 @@ import java.util.Objects; import org.apache.datasketches.memory.BaseState; import org.apache.datasketches.memory.MemoryRequestServer; +import org.apache.datasketches.memory.MemoryScope; import org.apache.datasketches.memory.WritableBuffer; import org.apache.datasketches.memory.WritableMemory; import jdk.incubator.foreign.MemoryAddress; import jdk.incubator.foreign.MemorySegment; -import jdk.incubator.foreign.ResourceScope; /** * Keeps key configuration state for MemoryImpl and BufferImpl plus some common static variables @@ -42,7 +42,7 @@ import jdk.incubator.foreign.ResourceScope; */ abstract class BaseStateImpl implements BaseState { static final String JDK; //must be at least "1.8" - static final int JDK_MAJOR; //8, 11, 12, etc + static final int JDK_MAJOR; //8, 11, 17, 21, etc static final int BOOLEAN_SHIFT = 0; static final int BYTE_SHIFT = 0; @@ -82,7 +82,7 @@ abstract class BaseStateImpl implements BaseState { JDK_MAJOR = (p[0] == 1) ? p[1] : p[0]; } - final MemorySegment seg; + final MemorySegment seg; //the single reference to the MemorySegment is kept here. final int typeId; MemoryRequestServer memReqSvr; @@ -388,8 +388,9 @@ abstract class BaseStateImpl implements BaseState { @Override public void load() { seg.load(); } + @SuppressWarnings("resource") @Override - public ResourceScope scope() { return seg.scope(); } + public MemoryScope scope() { return new MemoryScopeImpl(seg.scope()); } // @Override // public void setMemoryRequestServer(final MemoryRequestServer memReqSvr) { diff --git a/src/main/java/org/apache/datasketches/memory/internal/BaseWritableBufferImpl.java b/src/main/java/org/apache/datasketches/memory/internal/BaseWritableBufferImpl.java index 68c9134..c89cf45 100644 --- a/src/main/java/org/apache/datasketches/memory/internal/BaseWritableBufferImpl.java +++ b/src/main/java/org/apache/datasketches/memory/internal/BaseWritableBufferImpl.java @@ -63,6 +63,15 @@ public abstract class BaseWritableBufferImpl extends BaseBufferImpl implements W //BYTE BUFFER RESOURCE + /** + * Creates a read-only or writable, Native or Non-native endian Buffer instance + * given a ByteBuffer. + * @param byteBuffer the given ByteBuffer + * @param localReadOnly the given requested readOnly state + * @param byteOrder the given byte-order + * @return a WritableMemory instance, which may be read-only. + * @throws IllegalArgumentException if ByteBuffer is not writable. + */ public static WritableBuffer wrapByteBuffer( final ByteBuffer byteBuffer, final boolean localReadOnly, diff --git a/src/main/java/org/apache/datasketches/memory/internal/BaseWritableMemoryImpl.java b/src/main/java/org/apache/datasketches/memory/internal/BaseWritableMemoryImpl.java index 61a5a70..97e5108 100644 --- a/src/main/java/org/apache/datasketches/memory/internal/BaseWritableMemoryImpl.java +++ b/src/main/java/org/apache/datasketches/memory/internal/BaseWritableMemoryImpl.java @@ -21,6 +21,7 @@ package org.apache.datasketches.memory.internal; import static java.nio.channels.FileChannel.MapMode.READ_ONLY; import static java.nio.channels.FileChannel.MapMode.READ_WRITE; +import static java.util.Objects.requireNonNull; import java.io.ByteArrayOutputStream; import java.io.File; @@ -28,17 +29,16 @@ import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.channels.FileChannel; -import java.util.Objects; import org.apache.datasketches.memory.Buffer; import org.apache.datasketches.memory.Memory; import org.apache.datasketches.memory.MemoryRequestServer; +import org.apache.datasketches.memory.MemoryScope; import org.apache.datasketches.memory.WritableBuffer; import org.apache.datasketches.memory.WritableMemory; import jdk.incubator.foreign.MemoryAccess; import jdk.incubator.foreign.MemorySegment; -import jdk.incubator.foreign.ResourceScope; /* * Developer notes: The heavier methods, such as put/get arrays, duplicate, region, clear, fill, @@ -68,13 +68,20 @@ public abstract class BaseWritableMemoryImpl extends BaseStateImpl implements Wr //WRAP HEAP ARRAY RESOURCE + /** + * Creates a read-only or writable, Native or Non-native endian Memory instance + * given a segment containing an arbitrary on-heap array. + * @param seg the given segment + * @param byteOrder the given byte-order + * @param memReqSvr a MemoryRequestServer or null + * @return a WritableMemory instance, which may be read-only. + */ public static WritableMemory wrapSegmentAsArray( final MemorySegment seg, final ByteOrder byteOrder, final MemoryRequestServer memReqSvr) { - Objects.requireNonNull(byteOrder, "byteOrder must be non-null"); - int type = MEMORY - | (seg.isReadOnly() ? READONLY : 0); + requireNonNull(byteOrder, "byteOrder must be non-null"); + int type = MEMORY | (seg.isReadOnly() ? READONLY : 0); if (byteOrder == NON_NATIVE_BYTE_ORDER) { type |= NONNATIVE; return new NonNativeWritableMemoryImpl(seg, type, memReqSvr); @@ -84,12 +91,21 @@ public abstract class BaseWritableMemoryImpl extends BaseStateImpl implements Wr //BYTE BUFFER RESOURCE + /** + * Creates a read-only or writable, Native or Non-native endian Memory instance + * given a ByteBuffer. + * @param byteBuffer the given ByteBuffer + * @param localReadOnly the given requested readOnly state + * @param byteOrder the given byte-order + * @return a WritableMemory instance, which may be read-only. + * @throws IllegalArgumentException if ByteBuffer is not writable. + */ public static WritableMemory wrapByteBuffer( final ByteBuffer byteBuffer, final boolean localReadOnly, final ByteOrder byteOrder) { - Objects.requireNonNull(byteBuffer, "ByteBuffer must not be null"); - Objects.requireNonNull(byteOrder, "ByteOrder must not be null"); + requireNonNull(byteBuffer, "ByteBuffer must not be null"); + requireNonNull(byteOrder, "ByteOrder must not be null"); final ByteBuffer byteBuf; if (localReadOnly) { if (byteBuffer.isReadOnly()) { @@ -121,23 +137,42 @@ public abstract class BaseWritableMemoryImpl extends BaseStateImpl implements Wr //MAP FILE RESOURCE + /** + * Creates a writable, Native or Non-native endian, memory-mapped Memory instance. + * @param file the given file + * @param fileOffsetBytes the given offset bytes in the file + * @param capacityBytes the size (in bytes) of the mapped memory backing the memory segment. + * @param memScope the MemoryScope that wraps the ResourceScope + * @param localReadOnly true if the returned segment is to be read-only + * @param byteOrder the give byte order + * @return a WritableMemory that wraps a MemorySegment + * @throws IllegalArgumentException if file is not writable + * @throws IllegalStateException during IO operations + * @throws IOException during IO operations + * @throws SecurityException due to IO security issues + */ @SuppressWarnings("resource") public static WritableMemory wrapMap( final File file, final long fileOffsetBytes, final long capacityBytes, - final ResourceScope scope, + final MemoryScope memScope, final boolean localReadOnly, final ByteOrder byteOrder) throws IllegalArgumentException, IllegalStateException, IOException, SecurityException { - Objects.requireNonNull(file, "File must be non-null."); - Objects.requireNonNull(byteOrder, "ByteOrder must be non-null."); - Objects.requireNonNull(scope, "ResourceScope must be non-null."); + requireNonNull(file, "File must be non-null."); + requireNonNull(byteOrder, "ByteOrder must be non-null."); + requireNonNull(memScope, "MemoryScope must be non-null."); if (!file.canRead()) { throw new IllegalArgumentException("File must be readable."); } if (!localReadOnly && !file.canWrite()) { throw new IllegalArgumentException("File must be writable."); } final FileChannel.MapMode mapMode = (localReadOnly) ? READ_ONLY : READ_WRITE; - final MemorySegment seg = MemorySegment.mapFile(file.toPath(), fileOffsetBytes, capacityBytes, mapMode, scope); + final MemorySegment seg = MemorySegment.mapFile( + file.toPath(), + fileOffsetBytes, + capacityBytes, + mapMode, + ((MemoryScopeImpl)memScope).getResourceScope()); final boolean nativeBOType = byteOrder == ByteOrder.nativeOrder(); final int type = MEMORY | MAP | DIRECT | (localReadOnly ? READONLY : 0) @@ -153,8 +188,8 @@ public abstract class BaseWritableMemoryImpl extends BaseStateImpl implements Wr * The static constructor that chooses the correct Direct leaf node based on the byte order. * @param capacityBytes the requested capacity for the Direct (off-heap) memory. It must be ≥ 0. * @param alignmentBytes requested segment alignment. Typically 1, 2, 4 or 8. - * @param scope ResourceScope for the backing MemorySegment. - * Typically <i>ResourceScope.newConfinedScope()</i>. + * @param memScope MemoryScope that wraps a ResourceScope for the backing MemorySegment. + * Typically <i>MemoryScope.newConfinedScope()</i>. * @param byteOrder the byte order to be used. 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. @@ -164,15 +199,15 @@ public abstract class BaseWritableMemoryImpl extends BaseStateImpl implements Wr public static WritableMemory wrapDirect( final long capacityBytes, final long alignmentBytes, - final ResourceScope scope, + final MemoryScope memScope, final ByteOrder byteOrder, final MemoryRequestServer memReqSvr) { - Objects.requireNonNull(scope, "ResourceScope must be non-null"); - Objects.requireNonNull(byteOrder, "ByteOrder must be non-null"); + requireNonNull(memScope, "MemoryScope must be non-null"); + requireNonNull(byteOrder, "ByteOrder must be non-null"); final MemorySegment seg = MemorySegment.allocateNative( capacityBytes, alignmentBytes, - scope); + ((MemoryScopeImpl)memScope).getResourceScope()); final boolean nativeBOType = byteOrder == ByteOrder.nativeOrder(); final int type = MEMORY | DIRECT | (nativeBOType ? NATIVE : NONNATIVE); @@ -202,7 +237,7 @@ public abstract class BaseWritableMemoryImpl extends BaseStateImpl implements Wr final boolean localReadOnly, final ByteOrder byteOrder) { if (!this.isAlive()) { throw new IllegalStateException("This Memory is not alive."); } - Objects.requireNonNull(byteOrder, "byteOrder must be non-null."); + requireNonNull(byteOrder, "byteOrder must be non-null."); final boolean readOnly = isReadOnly() || localReadOnly; final MemorySegment slice = (readOnly && !seg.isReadOnly()) ? seg.asSlice(offsetBytes, capacityBytes).asReadOnly() @@ -242,7 +277,7 @@ public abstract class BaseWritableMemoryImpl extends BaseStateImpl implements Wr private WritableBuffer asWritableBufferImpl(final boolean localReadOnly, final ByteOrder byteOrder) { if (!this.isAlive()) { throw new IllegalStateException("This Memory is not alive."); } - Objects.requireNonNull(byteOrder, "byteOrder must be non-null"); + requireNonNull(byteOrder, "byteOrder must be non-null"); final boolean readOnly = isReadOnly() || localReadOnly; final MemorySegment seg2 = (readOnly && !seg.isReadOnly()) ? seg.asReadOnly() : seg; final boolean regionType = isRegion(); diff --git a/src/main/java/org/apache/datasketches/memory/internal/MemoryScopeImpl.java b/src/main/java/org/apache/datasketches/memory/internal/MemoryScopeImpl.java new file mode 100644 index 0000000..8b022d7 --- /dev/null +++ b/src/main/java/org/apache/datasketches/memory/internal/MemoryScopeImpl.java @@ -0,0 +1,157 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.datasketches.memory.internal; + +import java.lang.ref.Cleaner; + +import org.apache.datasketches.memory.MemoryScope; + +import jdk.incubator.foreign.ResourceScope; + +/** + * Implementation of MemoryScope + */ +@SuppressWarnings("resource") +public class MemoryScopeImpl extends MemoryScope { + private ResourceScope resourceScope; + + /** + * Constructor + * @param resourceScope the given ResourceScope. + */ + public MemoryScopeImpl(final ResourceScope resourceScope) { + this.resourceScope = resourceScope; + } + + /** + * Gets the GlobalScope + * @return the MemoryScope + */ + public static MemoryScope getGlobalScope() { + return new MemoryScopeImpl(ResourceScope.globalScope()); + } + + /** + * Gets a new ConfinedScope + * @return the MemoryScope + */ + public static MemoryScope getNewConfinedScope() { + return new MemoryScopeImpl(ResourceScope.newConfinedScope()); + } + + /** + * Gets a new ConfinedScope with Cleaner + * @param cleaner the given Cleaner + * @return the MemoryScope + */ + public static MemoryScope getNewConfinedScope(final Cleaner cleaner) { + return new MemoryScopeImpl(ResourceScope.newConfinedScope(cleaner)); + } + + /** + * Gets a new SharedScope + * @return the MemoryScope + */ + public static MemoryScope getNewSharedScope() { + return new MemoryScopeImpl(ResourceScope.newSharedScope()); + } + + /** + * Gets a new SharedScope with Cleaner + * @param cleaner the given Cleaner + * @return the MemoryScope + */ + public static MemoryScope getNewSharedScope(final Cleaner cleaner) { + return new MemoryScopeImpl(ResourceScope.newSharedScope(cleaner)); + } + + @Override + public Handle acquire() { + return new HandleImpl(); + } + + @Override + public void addCloseAction(final Runnable runnable) { + resourceScope.addCloseAction(runnable); + } + + @Override + public void close() { + if (resourceScope != null) { + resourceScope.close(); + } + } + + /** + * Returns the underlying <i>ResourceScope</i>. + * @return the underlying <i>ResourceScope</i>. + */ + public ResourceScope getResourceScope() { + return resourceScope; + } + + @Override + public boolean isAlive() { + return resourceScope.isAlive(); + } + + @Override + public boolean isImplicit() { + return resourceScope.isImplicit(); + } + + @Override + public Thread ownerThread() { + return resourceScope.ownerThread(); + } + + @Override + public void release(final MemoryScope.Handle handle) { + final HandleImpl handleImpl = (MemoryScopeImpl.HandleImpl) handle; + if (handleImpl.scope() == this) { + handleImpl.release(handleImpl); + } + } + + /** + * Implements a handle for this <i>MemoryScope</i>. + */ + public class HandleImpl extends MemoryScope.Handle { + private ResourceScope.Handle myResourceHandle; + + /** + * Constructor + */ + public HandleImpl() { + this.myResourceHandle = resourceScope.acquire(); + } + + @Override + public MemoryScope scope() { return MemoryScopeImpl.this; } + + @Override + public void release(final MemoryScope.Handle handle) { + if ((MemoryScopeImpl.HandleImpl) handle == myResourceHandle) { + MemoryScopeImpl.this.resourceScope.release(myResourceHandle); + } + } + } + +} diff --git a/src/main/java/org/apache/datasketches/memory/internal/NativeWritableBufferImpl.java b/src/main/java/org/apache/datasketches/memory/internal/NativeWritableBufferImpl.java index e5ec5ba..ccc7a40 100644 --- a/src/main/java/org/apache/datasketches/memory/internal/NativeWritableBufferImpl.java +++ b/src/main/java/org/apache/datasketches/memory/internal/NativeWritableBufferImpl.java @@ -45,7 +45,7 @@ import jdk.incubator.foreign.MemorySegment; */ final class NativeWritableBufferImpl extends BaseWritableBufferImpl { - //Pass-through ctor + //All native endian, read-only and writable Buffer instances start initialization here NativeWritableBufferImpl( final MemorySegment seg, final int typeId, diff --git a/src/main/java/org/apache/datasketches/memory/internal/NativeWritableMemoryImpl.java b/src/main/java/org/apache/datasketches/memory/internal/NativeWritableMemoryImpl.java index 41cb9b6..5233ab2 100644 --- a/src/main/java/org/apache/datasketches/memory/internal/NativeWritableMemoryImpl.java +++ b/src/main/java/org/apache/datasketches/memory/internal/NativeWritableMemoryImpl.java @@ -44,7 +44,7 @@ import jdk.incubator.foreign.MemorySegment; */ final class NativeWritableMemoryImpl extends BaseWritableMemoryImpl { - //Pass-through ctor + //All native endian, read-only and writable Memory instances start initialization here NativeWritableMemoryImpl( final MemorySegment seg, final int typeId, diff --git a/src/main/java/org/apache/datasketches/memory/internal/NonNativeWritableBufferImpl.java b/src/main/java/org/apache/datasketches/memory/internal/NonNativeWritableBufferImpl.java index a27878e..44880e7 100644 --- a/src/main/java/org/apache/datasketches/memory/internal/NonNativeWritableBufferImpl.java +++ b/src/main/java/org/apache/datasketches/memory/internal/NonNativeWritableBufferImpl.java @@ -45,7 +45,7 @@ import jdk.incubator.foreign.MemorySegment; */ final class NonNativeWritableBufferImpl extends BaseWritableBufferImpl { - //Pass-through ctor + //All non-native endian, read-only and writable Buffer instances start initialization here NonNativeWritableBufferImpl( final MemorySegment seg, final int typeId, diff --git a/src/main/java/org/apache/datasketches/memory/internal/NonNativeWritableMemoryImpl.java b/src/main/java/org/apache/datasketches/memory/internal/NonNativeWritableMemoryImpl.java index c699e8e..ba5b478 100644 --- a/src/main/java/org/apache/datasketches/memory/internal/NonNativeWritableMemoryImpl.java +++ b/src/main/java/org/apache/datasketches/memory/internal/NonNativeWritableMemoryImpl.java @@ -44,7 +44,7 @@ import jdk.incubator.foreign.MemorySegment; */ final class NonNativeWritableMemoryImpl extends BaseWritableMemoryImpl { - //Pass-through ctor + //All non-native endian, read-only and writable Memory instances start initialization here NonNativeWritableMemoryImpl( final MemorySegment seg, final int typeId, --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
