You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by dp...@apache.org on 2019/04/11 12:18:08 UTC
[ignite] branch ignite-2.7.5 updated: IGNITE-11600: Fix GridUnsafe
for Java 12: Selective prioritized approaches to allocate a direct buffer
(#6384)
This is an automated email from the ASF dual-hosted git repository.
dpavlov pushed a commit to branch ignite-2.7.5
in repository https://gitbox.apache.org/repos/asf/ignite.git
The following commit(s) were added to refs/heads/ignite-2.7.5 by this push:
new 266a741 IGNITE-11600: Fix GridUnsafe for Java 12: Selective prioritized approaches to allocate a direct buffer (#6384)
266a741 is described below
commit 266a7418e98b5e2bccb3c833cc3fdd1616917833
Author: Dmitriy Pavlov <dp...@apache.org>
AuthorDate: Thu Apr 11 15:07:10 2019 +0300
IGNITE-11600: Fix GridUnsafe for Java 12: Selective prioritized approaches to allocate a direct buffer (#6384)
(cherry picked from commit 3064f1ee56f420d64129ad59d9191296d8f249a7)
---
.../apache/ignite/internal/util/GridUnsafe.java | 178 ++++++++++++++++++++-
1 file changed, 170 insertions(+), 8 deletions(-)
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/GridUnsafe.java b/modules/core/src/main/java/org/apache/ignite/internal/util/GridUnsafe.java
index c882712..37bd99e 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/util/GridUnsafe.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/util/GridUnsafe.java
@@ -17,6 +17,7 @@
package org.apache.ignite.internal.util;
+import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@@ -28,7 +29,9 @@ import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import org.apache.ignite.IgniteSystemProperties;
+import org.apache.ignite.internal.util.typedef.internal.A;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import sun.misc.Unsafe;
import static org.apache.ignite.internal.util.IgniteUtils.jdkVersion;
@@ -108,11 +111,79 @@ public abstract class GridUnsafe {
? new ReflectiveDirectBufferCleaner()
: new UnsafeDirectBufferCleaner();
- /** JavaNioAccess object. */
- private static final Object JAVA_NIO_ACCESS_OBJ = javaNioAccessObject();
+ /** JavaNioAccess object. If {@code null} then {@link #NEW_DIRECT_BUF_CONSTRUCTOR} should be available. */
+ @Nullable private static final Object JAVA_NIO_ACCESS_OBJ;
- /** JavaNioAccess#newDirectByteBuffer method. */
- private static final Method NEW_DIRECT_BUF_MTD = newDirectBufferMethod();
+ /**
+ * JavaNioAccess#newDirectByteBuffer method. Ususally {@code null} if {@link #JAVA_NIO_ACCESS_OBJ} is {@code null}.
+ * If {@code null} then {@link #NEW_DIRECT_BUF_CONSTRUCTOR} should be available.
+ */
+ @Nullable private static final Method NEW_DIRECT_BUF_MTD;
+
+ /**
+ * New direct buffer class constructor obtained and tested using reflection. If {@code null} then both {@link
+ * #JAVA_NIO_ACCESS_OBJ} and {@link #NEW_DIRECT_BUF_MTD} should be not {@code null}.
+ */
+ @Nullable private static final Constructor<?> NEW_DIRECT_BUF_CONSTRUCTOR;
+
+ static {
+ Object nioAccessObj = null;
+ Method directBufMtd = null;
+
+ Constructor<?> directBufCtor = null;
+
+ if (majorJavaVersion(jdkVersion()) < 12) {
+ // for old java prefer Java NIO & Shared Secrets obect init way
+ try {
+ nioAccessObj = javaNioAccessObject();
+ directBufMtd = newDirectBufferMethod(nioAccessObj);
+ }
+ catch (Exception e) {
+ nioAccessObj = null;
+ directBufMtd = null;
+
+ try {
+ directBufCtor = createAndTestNewDirectBufferCtor();
+ }
+ catch (Exception eFallback) {
+ eFallback.printStackTrace();
+
+ e.addSuppressed(eFallback);
+
+ throw e; // fallback was not suceefull
+ }
+
+ if (directBufCtor == null)
+ throw e;
+ }
+ }
+ else {
+ try {
+ directBufCtor = createAndTestNewDirectBufferCtor();
+ }
+ catch (Exception e) {
+ try {
+ nioAccessObj = javaNioAccessObject();
+ directBufMtd = newDirectBufferMethod(nioAccessObj);
+ }
+ catch (Exception eFallback) {
+ eFallback.printStackTrace();
+
+ e.addSuppressed(eFallback);
+
+ throw e; //fallback to shared secrets failed.
+ }
+
+ if (nioAccessObj == null || directBufMtd == null)
+ throw e;
+ }
+ }
+
+ JAVA_NIO_ACCESS_OBJ = nioAccessObj;
+ NEW_DIRECT_BUF_MTD = directBufMtd;
+
+ NEW_DIRECT_BUF_CONSTRUCTOR = directBufCtor;
+ }
/**
* Ensure singleton.
@@ -122,13 +193,56 @@ public abstract class GridUnsafe {
}
/**
+ * Wraps pointer to unmanaged memory into direct byte buffer.
+ *
* @param ptr Pointer to wrap.
* @param len Memory location length.
* @return Byte buffer wrapping the given memory.
*/
public static ByteBuffer wrapPointer(long ptr, int len) {
+ if (NEW_DIRECT_BUF_MTD != null && JAVA_NIO_ACCESS_OBJ != null)
+ return wrapPointerJavaNio(ptr, len, NEW_DIRECT_BUF_MTD, JAVA_NIO_ACCESS_OBJ);
+ else if (NEW_DIRECT_BUF_CONSTRUCTOR != null)
+ return wrapPointerDirectBufCtor(ptr, len, NEW_DIRECT_BUF_CONSTRUCTOR);
+ else
+ throw new RuntimeException("All alternative for a new DirectByteBuffer() creation failed: " + FeatureChecker.JAVA_VER_SPECIFIC_WARN);
+ }
+
+ /**
+ * Wraps pointer to unmanaged memory into direct byte buffer. Uses constructor of a direct byte buffer.
+ *
+ * @param ptr Pointer to wrap.
+ * @param len Memory location length.
+ * @param constructor Constructor to use. Should create an instance of a direct ByteBuffer.
+ * @return Byte buffer wrapping the given memory.
+ */
+ @NotNull private static ByteBuffer wrapPointerDirectBufCtor(long ptr, int len, Constructor<?> constructor) {
try {
- ByteBuffer buf = (ByteBuffer)NEW_DIRECT_BUF_MTD.invoke(JAVA_NIO_ACCESS_OBJ, ptr, len, null);
+ Object newDirectBuf = constructor.newInstance(ptr, len);
+
+ return ((ByteBuffer)newDirectBuf).order(NATIVE_BYTE_ORDER);
+ }
+ catch (ReflectiveOperationException e) {
+ throw new RuntimeException("DirectByteBuffer#constructor is unavailable."
+ + FeatureChecker.JAVA_VER_SPECIFIC_WARN, e);
+ }
+ }
+
+ /**
+ * Wraps pointer to unmanaged memory into direct byte buffer. Uses JavaNioAccess object.
+ *
+ * @param ptr Pointer to wrap.
+ * @param len Memory location length.
+ * @param newDirectBufMtd Method which should return an instance of a direct byte buffer.
+ * @param javaNioAccessObj Object to invoke method.
+ * @return Byte buffer wrapping the given memory.
+ */
+ @NotNull private static ByteBuffer wrapPointerJavaNio(long ptr,
+ int len,
+ @NotNull Method newDirectBufMtd,
+ @NotNull Object javaNioAccessObj) {
+ try {
+ ByteBuffer buf = (ByteBuffer)newDirectBufMtd.invoke(javaNioAccessObj, ptr, len, null);
assert buf.isDirect();
@@ -1460,13 +1574,13 @@ public abstract class GridUnsafe {
* Returns reference to {@code JavaNioAccess.newDirectByteBuffer} method
* from private API for corresponding Java version.
*
+ * @param nioAccessObj Java NIO access object.
* @return Reference to {@code JavaNioAccess.newDirectByteBuffer} method
* @throws RuntimeException If getting access to the private API is failed.
*/
- private static Method newDirectBufferMethod() {
-
+ private static Method newDirectBufferMethod(Object nioAccessObj) {
try {
- Class<?> cls = JAVA_NIO_ACCESS_OBJ.getClass();
+ Class<?> cls = nioAccessObj.getClass();
Method mtd = cls.getMethod("newDirectByteBuffer", long.class, int.class, Object.class);
@@ -1487,6 +1601,54 @@ public abstract class GridUnsafe {
return javaVer < 9 ? "sun" : "jdk.internal";
}
+
+ /**
+ * Creates and tests contructor for Direct ByteBuffer. Test is wrapping one-byte unsafe memory into a buffer.
+ *
+ * @return constructor for creating direct ByteBuffers.
+ */
+ @NotNull
+ private static Constructor<?> createAndTestNewDirectBufferCtor() {
+ Constructor<?> ctorCandidate = createNewDirectBufferCtor();
+
+ int l = 1;
+ long ptr = UNSAFE.allocateMemory(l);
+
+ try {
+ ByteBuffer buf = wrapPointerDirectBufCtor(ptr, l, ctorCandidate);
+
+ A.ensure(buf.isDirect(), "Buffer expected to be direct, internal error during #wrapPointerDirectBufCtor()");
+ }
+ finally {
+ UNSAFE.freeMemory(ptr);
+ }
+
+ return ctorCandidate;
+ }
+
+
+ /**
+ * Simply create some instance of direct Byte Buffer and try to get it's class declared constructor.
+ *
+ * @return constructor for creating direct ByteBuffers.
+ */
+ @NotNull
+ private static Constructor<?> createNewDirectBufferCtor() {
+ try {
+ ByteBuffer buf = ByteBuffer.allocateDirect(1).order(NATIVE_BYTE_ORDER);
+
+ Constructor<?> ctor = buf.getClass().getDeclaredConstructor(long.class, int.class);
+
+ ctor.setAccessible(true);
+
+ return ctor;
+ }
+ catch (NoSuchMethodException | SecurityException e) {
+ throw new RuntimeException("Unable to set up byte buffer creation using reflections :" + e.getMessage(), e);
+ }
+ }
+
+
/**
* @param obj Object.
* @param off Offset.