X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=blobdiff_plain;f=third-party%2Fatomix%2Fstorage%2Fsrc%2Fmain%2Fjava%2Fio%2Fatomix%2Fstorage%2Fjournal%2FBufferCleaner.java;fp=third-party%2Fatomix%2Fstorage%2Fsrc%2Fmain%2Fjava%2Fio%2Fatomix%2Fstorage%2Fjournal%2FBufferCleaner.java;h=0000000000000000000000000000000000000000;hp=b67c8f4a2c6b662497dc950b1bdc67b3c560fc43;hb=16bcd8d75886f4d9d8ad4e6833147aa516358adf;hpb=e485516b27114195b1be7392dc4d71be49fd54bb diff --git a/third-party/atomix/storage/src/main/java/io/atomix/storage/journal/BufferCleaner.java b/third-party/atomix/storage/src/main/java/io/atomix/storage/journal/BufferCleaner.java deleted file mode 100644 index b67c8f4a2c..0000000000 --- a/third-party/atomix/storage/src/main/java/io/atomix/storage/journal/BufferCleaner.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright 2019-present Open Networking Foundation - * - * Licensed 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 io.atomix.storage.journal; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.nio.ByteBuffer; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.util.Objects; - -import static java.lang.invoke.MethodHandles.constant; -import static java.lang.invoke.MethodHandles.dropArguments; -import static java.lang.invoke.MethodHandles.filterReturnValue; -import static java.lang.invoke.MethodHandles.guardWithTest; -import static java.lang.invoke.MethodHandles.lookup; -import static java.lang.invoke.MethodType.methodType; - -/** - * Utility class which allows explicit calls to the DirectByteBuffer cleaner method instead of relying on GC. - */ -public class BufferCleaner { - - private static final Logger LOGGER = LoggerFactory.getLogger(BufferCleaner.class); - - /** - * Reference to a Cleaner that does unmapping; no-op if not supported. - */ - private static final Cleaner CLEANER; - - static { - final Object hack = AccessController.doPrivileged((PrivilegedAction) BufferCleaner::unmapHackImpl); - if (hack instanceof Cleaner) { - CLEANER = (Cleaner) hack; - LOGGER.debug("java.nio.DirectByteBuffer.cleaner(): available"); - } else { - CLEANER = (ByteBuffer buffer) -> { - // noop - }; - LOGGER.debug("java.nio.DirectByteBuffer.cleaner(): unavailable: {}", hack); - } - } - - private static Object unmapHackImpl() { - final MethodHandles.Lookup lookup = lookup(); - try { - try { - // *** sun.misc.Unsafe unmapping (Java 9+) *** - final Class unsafeClass = Class.forName("sun.misc.Unsafe"); - // first check if Unsafe has the right method, otherwise we can give up - // without doing any security critical stuff: - final MethodHandle unmapper = lookup.findVirtual(unsafeClass, "invokeCleaner", - methodType(void.class, ByteBuffer.class)); - // fetch the unsafe instance and bind it to the virtual MH: - final Field f = unsafeClass.getDeclaredField("theUnsafe"); - f.setAccessible(true); - final Object theUnsafe = f.get(null); - return newBufferCleaner(ByteBuffer.class, unmapper.bindTo(theUnsafe)); - } catch (SecurityException se) { - // rethrow to report errors correctly (we need to catch it here, as we also catch RuntimeException below!): - throw se; - } catch (ReflectiveOperationException | RuntimeException e) { - // *** sun.misc.Cleaner unmapping (Java 8) *** - final Class directBufferClass = Class.forName("java.nio.DirectByteBuffer"); - - final Method m = directBufferClass.getMethod("cleaner"); - m.setAccessible(true); - final MethodHandle directBufferCleanerMethod = lookup.unreflect(m); - final Class cleanerClass = directBufferCleanerMethod.type().returnType(); - - /* "Compile" a MH that basically is equivalent to the following code: - * void unmapper(ByteBuffer byteBuffer) { - * sun.misc.Cleaner cleaner = ((java.nio.DirectByteBuffer) byteBuffer).cleaner(); - * if (Objects.nonNull(cleaner)) { - * cleaner.clean(); - * } else { - * noop(cleaner); // the noop is needed because MethodHandles#guardWithTest always needs ELSE - * } - * } - */ - final MethodHandle cleanMethod = lookup.findVirtual(cleanerClass, "clean", methodType(void.class)); - final MethodHandle nonNullTest = lookup.findStatic(Objects.class, "nonNull", methodType(boolean.class, Object.class)) - .asType(methodType(boolean.class, cleanerClass)); - final MethodHandle noop = dropArguments(constant(Void.class, null).asType(methodType(void.class)), 0, cleanerClass); - final MethodHandle unmapper = filterReturnValue(directBufferCleanerMethod, guardWithTest(nonNullTest, cleanMethod, noop)) - .asType(methodType(void.class, ByteBuffer.class)); - return newBufferCleaner(directBufferClass, unmapper); - } - } catch (SecurityException se) { - return "Unmapping is not supported, because not all required permissions are given to the Lucene JAR file: " - + se + " [Please grant at least the following permissions: RuntimePermission(\"accessClassInPackage.sun.misc\") " - + " and ReflectPermission(\"suppressAccessChecks\")]"; - } catch (ReflectiveOperationException | RuntimeException e) { - return "Unmapping is not supported on this platform, because internal Java APIs are not compatible with this Atomix version: " + e; - } - } - - private static Cleaner newBufferCleaner(final Class unmappableBufferClass, final MethodHandle unmapper) { - return (ByteBuffer buffer) -> { - if (!buffer.isDirect()) { - return; - } - if (!unmappableBufferClass.isInstance(buffer)) { - throw new IllegalArgumentException("buffer is not an instance of " + unmappableBufferClass.getName()); - } - final Throwable error = AccessController.doPrivileged((PrivilegedAction) () -> { - try { - unmapper.invokeExact(buffer); - return null; - } catch (Throwable t) { - return t; - } - }); - if (error != null) { - throw new IOException("Unable to unmap the mapped buffer", error); - } - }; - } - - /** - * Free {@link ByteBuffer} if possible. - */ - public static void freeBuffer(ByteBuffer buffer) throws IOException { - CLEANER.freeBuffer(buffer); - } -}