From 9b8692c6a4c75b7df29a58b5d3d1d1ee5cb0c3a4 Mon Sep 17 00:00:00 2001 From: Benjamin Lerer Date: Tue, 28 Mar 2017 16:09:59 +0200 Subject: [PATCH] Use the Kernel32 library to retrieve the PID on Windows and fix startup checks patch by Benjamin Lerer; reviewed by Michael Kjellman for CASSANDRA-13333 --- CHANGES.txt | 1 + NEWS.txt | 9 +++ .../db/commitlog/CommitLogSegment.java | 4 +- .../db/commitlog/MemoryMappedSegment.java | 4 +- .../cassandra/db/lifecycle/LogReplica.java | 10 +-- .../apache/cassandra/hints/HintsCatalog.java | 6 +- .../apache/cassandra/hints/HintsReader.java | 4 +- .../apache/cassandra/hints/HintsWriter.java | 6 +- .../cassandra/io/sstable/SSTableRewriter.java | 4 +- .../io/sstable/format/SSTableReader.java | 4 +- .../cassandra/io/util/ChannelProxy.java | 4 +- .../cassandra/io/util/SegmentedFile.java | 4 +- .../cassandra/service/CassandraDaemon.java | 6 +- .../cassandra/service/NativeAccessMBean.java | 8 +++ .../cassandra/service/StartupChecks.java | 10 +-- .../org/apache/cassandra/utils/HeapUtils.java | 2 +- .../{CLibrary.java => NativeLibrary.java} | 46 +++++++------ ...ryDarwin.java => NativeLibraryDarwin.java} | 22 +++---- ...raryLinux.java => NativeLibraryLinux.java} | 22 +++---- ...Windows.java => NativeLibraryWindows.java} | 65 ++++++++++++------- ...Wrapper.java => NativeLibraryWrapper.java} | 10 ++- .../org/apache/cassandra/utils/SyncUtil.java | 6 +- .../org/apache/cassandra/utils/UUIDGen.java | 2 +- .../apache/cassandra/utils/WindowsTimer.java | 4 ++ ...ibraryTest.java => NativeLibraryTest.java} | 6 +- 25 files changed, 158 insertions(+), 111 deletions(-) rename src/java/org/apache/cassandra/utils/{CLibrary.java => NativeLibrary.java} (88%) rename src/java/org/apache/cassandra/utils/{CLibraryDarwin.java => NativeLibraryDarwin.java} (88%) rename src/java/org/apache/cassandra/utils/{CLibraryLinux.java => NativeLibraryLinux.java} (88%) rename src/java/org/apache/cassandra/utils/{CLibraryWindows.java => NativeLibraryWindows.java} (62%) rename src/java/org/apache/cassandra/utils/{CLibraryWrapper.java => NativeLibraryWrapper.java} (87%) rename test/unit/org/apache/cassandra/utils/{CLibraryTest.java => NativeLibraryTest.java} (89%) diff --git a/CHANGES.txt b/CHANGES.txt index 0af7a7de2f..ca79a01c59 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ 3.0.13 + * Use the Kernel32 library to retrieve the PID on Windows and fix startup checks (CASSANDRA-13333) * Fix code to not exchange schema across major versions (CASSANDRA-13274) * Dropping column results in "corrupt" SSTable (CASSANDRA-13337) * Bugs handling range tombstones in the sstable iterators (CASSANDRA-13340) diff --git a/NEWS.txt b/NEWS.txt index faba34225b..b6faef47fc 100644 --- a/NEWS.txt +++ b/NEWS.txt @@ -13,6 +13,15 @@ restore snapshots created with the previous major version using the 'sstableloader' tool. You can upgrade the file format of your snapshots using the provided 'sstableupgrade' tool. +3.0.13 +====== + +Upgrading +--------- + - The NativeAccessMBean isAvailable method will only return true if the + native library has been successfully linked. Previously it was returning + true if JNA could be found but was not taking into account link failures. + 3.0.12 ====== diff --git a/src/java/org/apache/cassandra/db/commitlog/CommitLogSegment.java b/src/java/org/apache/cassandra/db/commitlog/CommitLogSegment.java index 0a03c3cb18..f26f0dc9ac 100644 --- a/src/java/org/apache/cassandra/db/commitlog/CommitLogSegment.java +++ b/src/java/org/apache/cassandra/db/commitlog/CommitLogSegment.java @@ -48,7 +48,7 @@ import org.apache.cassandra.db.Mutation; import org.apache.cassandra.db.partitions.PartitionUpdate; import org.apache.cassandra.io.FSWriteError; import org.apache.cassandra.io.util.FileUtils; -import org.apache.cassandra.utils.CLibrary; +import org.apache.cassandra.utils.NativeLibrary; import org.apache.cassandra.utils.IntegerInterval; import org.apache.cassandra.utils.concurrent.OpOrder; import org.apache.cassandra.utils.concurrent.WaitQueue; @@ -156,7 +156,7 @@ public abstract class CommitLogSegment try { channel = FileChannel.open(logFile.toPath(), StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE); - fd = CLibrary.getfd(channel); + fd = NativeLibrary.getfd(channel); } catch (IOException e) { diff --git a/src/java/org/apache/cassandra/db/commitlog/MemoryMappedSegment.java b/src/java/org/apache/cassandra/db/commitlog/MemoryMappedSegment.java index afc8dccaf7..326469ffdc 100644 --- a/src/java/org/apache/cassandra/db/commitlog/MemoryMappedSegment.java +++ b/src/java/org/apache/cassandra/db/commitlog/MemoryMappedSegment.java @@ -25,7 +25,7 @@ import java.nio.channels.FileChannel; import org.apache.cassandra.config.DatabaseDescriptor; import org.apache.cassandra.io.FSWriteError; import org.apache.cassandra.io.util.FileUtils; -import org.apache.cassandra.utils.CLibrary; +import org.apache.cassandra.utils.NativeLibrary; import org.apache.cassandra.utils.SyncUtil; /* @@ -86,7 +86,7 @@ public class MemoryMappedSegment extends CommitLogSegment { throw new FSWriteError(e, getPath()); } - CLibrary.trySkipCache(fd, startMarker, nextMarker, logFile.getAbsolutePath()); + NativeLibrary.trySkipCache(fd, startMarker, nextMarker, logFile.getAbsolutePath()); } @Override diff --git a/src/java/org/apache/cassandra/db/lifecycle/LogReplica.java b/src/java/org/apache/cassandra/db/lifecycle/LogReplica.java index 712a22ddb0..44400d1011 100644 --- a/src/java/org/apache/cassandra/db/lifecycle/LogReplica.java +++ b/src/java/org/apache/cassandra/db/lifecycle/LogReplica.java @@ -21,7 +21,7 @@ package org.apache.cassandra.db.lifecycle; import java.io.File; import org.apache.cassandra.io.util.FileUtils; -import org.apache.cassandra.utils.CLibrary; +import org.apache.cassandra.utils.NativeLibrary; /** * Because a column family may have sstables on different disks and disks can @@ -41,12 +41,12 @@ final class LogReplica implements AutoCloseable static LogReplica create(File folder, String fileName) { - return new LogReplica(new File(fileName), CLibrary.tryOpenDirectory(folder.getPath())); + return new LogReplica(new File(fileName), NativeLibrary.tryOpenDirectory(folder.getPath())); } static LogReplica open(File file) { - return new LogReplica(file, CLibrary.tryOpenDirectory(file.getParentFile().getPath())); + return new LogReplica(file, NativeLibrary.tryOpenDirectory(file.getParentFile().getPath())); } LogReplica(File file, int folderDescriptor) @@ -74,7 +74,7 @@ final class LogReplica implements AutoCloseable void syncFolder() { if (folderDescriptor >= 0) - CLibrary.trySync(folderDescriptor); + NativeLibrary.trySync(folderDescriptor); } void delete() @@ -92,7 +92,7 @@ final class LogReplica implements AutoCloseable { if (folderDescriptor >= 0) { - CLibrary.tryCloseFD(folderDescriptor); + NativeLibrary.tryCloseFD(folderDescriptor); folderDescriptor = -1; } } diff --git a/src/java/org/apache/cassandra/hints/HintsCatalog.java b/src/java/org/apache/cassandra/hints/HintsCatalog.java index c2f0972085..5ebe65bf3d 100644 --- a/src/java/org/apache/cassandra/hints/HintsCatalog.java +++ b/src/java/org/apache/cassandra/hints/HintsCatalog.java @@ -27,7 +27,7 @@ import java.util.stream.Stream; import com.google.common.collect.ImmutableMap; import org.apache.cassandra.io.FSReadError; -import org.apache.cassandra.utils.CLibrary; +import org.apache.cassandra.utils.NativeLibrary; import org.apache.cassandra.utils.SyncUtil; import static java.util.stream.Collectors.groupingBy; @@ -130,11 +130,11 @@ final class HintsCatalog void fsyncDirectory() { - int fd = CLibrary.tryOpenDirectory(hintsDirectory.getAbsolutePath()); + int fd = NativeLibrary.tryOpenDirectory(hintsDirectory.getAbsolutePath()); if (fd != -1) { SyncUtil.trySync(fd); - CLibrary.tryCloseFD(fd); + NativeLibrary.tryCloseFD(fd); } } diff --git a/src/java/org/apache/cassandra/hints/HintsReader.java b/src/java/org/apache/cassandra/hints/HintsReader.java index ef24aca3e4..d88c4f5820 100644 --- a/src/java/org/apache/cassandra/hints/HintsReader.java +++ b/src/java/org/apache/cassandra/hints/HintsReader.java @@ -35,7 +35,7 @@ import org.apache.cassandra.io.FSReadError; import org.apache.cassandra.service.StorageService; import org.apache.cassandra.utils.AbstractIterator; import org.apache.cassandra.utils.ByteBufferUtil; -import org.apache.cassandra.utils.CLibrary; +import org.apache.cassandra.utils.NativeLibrary; /** * A paged non-compressed hints reader that provides two iterators: @@ -148,7 +148,7 @@ class HintsReader implements AutoCloseable, Iterable @SuppressWarnings("resource") protected Page computeNext() { - CLibrary.trySkipCache(input.getChannel().getFileDescriptor(), 0, input.getFilePointer(), input.getPath()); + NativeLibrary.trySkipCache(input.getChannel().getFileDescriptor(), 0, input.getFilePointer(), input.getPath()); if (input.isEOF()) return endOfData(); diff --git a/src/java/org/apache/cassandra/hints/HintsWriter.java b/src/java/org/apache/cassandra/hints/HintsWriter.java index 8836258e9d..31a440d888 100644 --- a/src/java/org/apache/cassandra/hints/HintsWriter.java +++ b/src/java/org/apache/cassandra/hints/HintsWriter.java @@ -34,7 +34,7 @@ import org.apache.cassandra.io.FSWriteError; import org.apache.cassandra.io.util.DataOutputBuffer; import org.apache.cassandra.io.util.DataOutputBufferFixed; import org.apache.cassandra.net.MessagingService; -import org.apache.cassandra.utils.CLibrary; +import org.apache.cassandra.utils.NativeLibrary; import org.apache.cassandra.utils.SyncUtil; import org.apache.cassandra.utils.Throwables; @@ -71,7 +71,7 @@ class HintsWriter implements AutoCloseable File file = new File(directory, descriptor.fileName()); FileChannel channel = FileChannel.open(file.toPath(), StandardOpenOption.WRITE, StandardOpenOption.CREATE_NEW); - int fd = CLibrary.getfd(channel); + int fd = NativeLibrary.getfd(channel); CRC32 crc = new CRC32(); @@ -293,7 +293,7 @@ class HintsWriter implements AutoCloseable // don't skip page cache for tiny files, on the assumption that if they are tiny, the target node is probably // alive, and if so, the file will be closed and dispatched shortly (within a minute), and the file will be dropped. if (position >= DatabaseDescriptor.getTrickleFsyncIntervalInKb() * 1024L) - CLibrary.trySkipCache(fd, 0, position - (position % PAGE_SIZE), file.getPath()); + NativeLibrary.trySkipCache(fd, 0, position - (position % PAGE_SIZE), file.getPath()); } } } diff --git a/src/java/org/apache/cassandra/io/sstable/SSTableRewriter.java b/src/java/org/apache/cassandra/io/sstable/SSTableRewriter.java index f4a2e1bc2c..0ea28d728e 100644 --- a/src/java/org/apache/cassandra/io/sstable/SSTableRewriter.java +++ b/src/java/org/apache/cassandra/io/sstable/SSTableRewriter.java @@ -32,7 +32,7 @@ import org.apache.cassandra.db.rows.UnfilteredRowIterator; import org.apache.cassandra.io.sstable.format.SSTableReader; import org.apache.cassandra.io.sstable.format.SSTableWriter; import org.apache.cassandra.db.lifecycle.LifecycleTransaction; -import org.apache.cassandra.utils.CLibrary; +import org.apache.cassandra.utils.NativeLibrary; import org.apache.cassandra.utils.concurrent.Transactional; /** @@ -164,7 +164,7 @@ public class SSTableRewriter extends Transactional.AbstractTransactional impleme for (SSTableReader reader : transaction.originals()) { RowIndexEntry index = reader.getPosition(key, SSTableReader.Operator.GE); - CLibrary.trySkipCache(reader.getFilename(), 0, index == null ? 0 : index.position); + NativeLibrary.trySkipCache(reader.getFilename(), 0, index == null ? 0 : index.position); } } else diff --git a/src/java/org/apache/cassandra/io/sstable/format/SSTableReader.java b/src/java/org/apache/cassandra/io/sstable/format/SSTableReader.java index 328372344d..8be1fe2e05 100644 --- a/src/java/org/apache/cassandra/io/sstable/format/SSTableReader.java +++ b/src/java/org/apache/cassandra/io/sstable/format/SSTableReader.java @@ -2223,8 +2223,8 @@ public abstract class SSTableReader extends SSTable implements SelfRefCounted= 0) return pid; diff --git a/src/java/org/apache/cassandra/utils/CLibrary.java b/src/java/org/apache/cassandra/utils/NativeLibrary.java similarity index 88% rename from src/java/org/apache/cassandra/utils/CLibrary.java rename to src/java/org/apache/cassandra/utils/NativeLibrary.java index 71f41489fc..f96859eac1 100644 --- a/src/java/org/apache/cassandra/utils/CLibrary.java +++ b/src/java/org/apache/cassandra/utils/NativeLibrary.java @@ -30,14 +30,14 @@ import org.slf4j.LoggerFactory; import com.sun.jna.LastErrorException; -import static org.apache.cassandra.utils.CLibrary.OSType.LINUX; -import static org.apache.cassandra.utils.CLibrary.OSType.MAC; -import static org.apache.cassandra.utils.CLibrary.OSType.WINDOWS; -import static org.apache.cassandra.utils.CLibrary.OSType.AIX; +import static org.apache.cassandra.utils.NativeLibrary.OSType.LINUX; +import static org.apache.cassandra.utils.NativeLibrary.OSType.MAC; +import static org.apache.cassandra.utils.NativeLibrary.OSType.WINDOWS; +import static org.apache.cassandra.utils.NativeLibrary.OSType.AIX; -public final class CLibrary +public final class NativeLibrary { - private static final Logger logger = LoggerFactory.getLogger(CLibrary.class); + private static final Logger logger = LoggerFactory.getLogger(NativeLibrary.class); public enum OSType { @@ -68,7 +68,7 @@ public final class CLibrary private static final int POSIX_FADV_DONTNEED = 4; /* fadvise.h */ private static final int POSIX_FADV_NOREUSE = 5; /* fadvise.h */ - private static final CLibraryWrapper wrappedCLibrary; + private static final NativeLibraryWrapper wrappedLibrary; private static boolean jnaLockable = false; static @@ -78,12 +78,12 @@ public final class CLibrary osType = getOsType(); switch (osType) { - case MAC: wrappedCLibrary = new CLibraryDarwin(); break; - case WINDOWS: wrappedCLibrary = new CLibraryWindows(); break; + case MAC: wrappedLibrary = new NativeLibraryDarwin(); break; + case WINDOWS: wrappedLibrary = new NativeLibraryWindows(); break; case LINUX: case AIX: case OTHER: - default: wrappedCLibrary = new CLibraryLinux(); + default: wrappedLibrary = new NativeLibraryLinux(); } if (System.getProperty("os.arch").toLowerCase().contains("ppc")) @@ -111,7 +111,7 @@ public final class CLibrary } } - private CLibrary() {} + private NativeLibrary() {} /** * @return the detected OSType of the Operating System running the JVM using crude string matching @@ -144,9 +144,13 @@ public final class CLibrary } } - public static boolean jnaAvailable() + /** + * Checks if the library has been successfully linked. + * @return {@code true} if the library has been successfully linked, {@code false} otherwise. + */ + public static boolean isAvailable() { - return wrappedCLibrary.jnaAvailable(); + return wrappedLibrary.isAvailable(); } public static boolean jnaMemoryLockable() @@ -158,7 +162,7 @@ public final class CLibrary { try { - wrappedCLibrary.callMlockall(MCL_CURRENT); + wrappedLibrary.callMlockall(MCL_CURRENT); jnaLockable = true; logger.info("JNA mlockall successful"); } @@ -224,14 +228,14 @@ public final class CLibrary { if (osType == LINUX) { - int result = wrappedCLibrary.callPosixFadvise(fd, offset, len, POSIX_FADV_DONTNEED); + int result = wrappedLibrary.callPosixFadvise(fd, offset, len, POSIX_FADV_DONTNEED); if (result != 0) NoSpamLogger.log( logger, NoSpamLogger.Level.WARN, 10, TimeUnit.MINUTES, - "Failed trySkipCache on file: {} Error: " + wrappedCLibrary.callStrerror(result).getString(0), + "Failed trySkipCache on file: {} Error: " + wrappedLibrary.callStrerror(result).getString(0), path); } } @@ -256,7 +260,7 @@ public final class CLibrary try { - result = wrappedCLibrary.callFcntl(fd, command, flags); + result = wrappedLibrary.callFcntl(fd, command, flags); } catch (UnsatisfiedLinkError e) { @@ -279,7 +283,7 @@ public final class CLibrary try { - return wrappedCLibrary.callOpen(path, O_RDONLY); + return wrappedLibrary.callOpen(path, O_RDONLY); } catch (UnsatisfiedLinkError e) { @@ -303,7 +307,7 @@ public final class CLibrary try { - wrappedCLibrary.callFsync(fd); + wrappedLibrary.callFsync(fd); } catch (UnsatisfiedLinkError e) { @@ -325,7 +329,7 @@ public final class CLibrary try { - wrappedCLibrary.callClose(fd); + wrappedLibrary.callClose(fd); } catch (UnsatisfiedLinkError e) { @@ -384,7 +388,7 @@ public final class CLibrary { try { - return wrappedCLibrary.callGetpid(); + return wrappedLibrary.callGetpid(); } catch (Exception e) { diff --git a/src/java/org/apache/cassandra/utils/CLibraryDarwin.java b/src/java/org/apache/cassandra/utils/NativeLibraryDarwin.java similarity index 88% rename from src/java/org/apache/cassandra/utils/CLibraryDarwin.java rename to src/java/org/apache/cassandra/utils/NativeLibraryDarwin.java index e0a43ec066..d6f1a9e887 100644 --- a/src/java/org/apache/cassandra/utils/CLibraryDarwin.java +++ b/src/java/org/apache/cassandra/utils/NativeLibraryDarwin.java @@ -26,7 +26,7 @@ import com.sun.jna.Native; import com.sun.jna.Pointer; /** - * A CLibraryWrapper implementation for Darwin/Mac. + * A {@code NativeLibraryWrapper} implementation for Darwin/Mac. *

* When JNA is initialized, all methods that have the 'native' keyword * will be attmpted to be linked against. As Java doesn't have the equivalent @@ -37,35 +37,33 @@ import com.sun.jna.Pointer; * native calls that are supported on that target operating system will be * unavailable simply because of one native defined method not supported * on the runtime operating system. - * @see org.apache.cassandra.utils.CLibraryWrapper - * @see CLibrary + * @see org.apache.cassandra.utils.NativeLibraryWrapper + * @see NativeLibrary */ -public class CLibraryDarwin implements CLibraryWrapper +public class NativeLibraryDarwin implements NativeLibraryWrapper { - private static final Logger logger = LoggerFactory.getLogger(CLibraryDarwin.class); + private static final Logger logger = LoggerFactory.getLogger(NativeLibraryDarwin.class); - private static boolean jnaAvailable = true; + private static boolean available; static { try { Native.register("c"); + available = true; } catch (NoClassDefFoundError e) { logger.warn("JNA not found. Native methods will be disabled."); - jnaAvailable = false; } catch (UnsatisfiedLinkError e) { - logger.warn("JNA link failure, one or more native method will be unavailable."); - logger.error("JNA link failure details: {}", e.getMessage()); + logger.error("Failed to link the C library against JNA. Native methods will be unavailable.", e); } catch (NoSuchMethodError e) { logger.warn("Obsolete version of JNA present; unable to register C library. Upgrade to JNA 3.2.7 or later"); - jnaAvailable = false; } } @@ -124,8 +122,8 @@ public class CLibraryDarwin implements CLibraryWrapper return getpid(); } - public boolean jnaAvailable() + public boolean isAvailable() { - return jnaAvailable; + return available; } } diff --git a/src/java/org/apache/cassandra/utils/CLibraryLinux.java b/src/java/org/apache/cassandra/utils/NativeLibraryLinux.java similarity index 88% rename from src/java/org/apache/cassandra/utils/CLibraryLinux.java rename to src/java/org/apache/cassandra/utils/NativeLibraryLinux.java index 1822bdf4bd..b6667e428f 100644 --- a/src/java/org/apache/cassandra/utils/CLibraryLinux.java +++ b/src/java/org/apache/cassandra/utils/NativeLibraryLinux.java @@ -26,7 +26,7 @@ import com.sun.jna.Native; import com.sun.jna.Pointer; /** - * A CLibraryWrapper implementation for Linux. + * A {@code NativeLibraryWrapper} implementation for Linux. *

* When JNA is initialized, all methods that have the 'native' keyword * will be attmpted to be linked against. As Java doesn't have the equivalent @@ -37,35 +37,33 @@ import com.sun.jna.Pointer; * native calls that are supported on that target operating system will be * unavailable simply because of one native defined method not supported * on the runtime operating system. - * @see org.apache.cassandra.utils.CLibraryWrapper - * @see CLibrary + * @see org.apache.cassandra.utils.NativeLibraryWrapper + * @see NativeLibrary */ -public class CLibraryLinux implements CLibraryWrapper +public class NativeLibraryLinux implements NativeLibraryWrapper { - private static boolean jnaAvailable = true; + private static boolean available; - private static final Logger logger = LoggerFactory.getLogger(CLibraryLinux.class); + private static final Logger logger = LoggerFactory.getLogger(NativeLibraryLinux.class); static { try { Native.register("c"); + available = true; } catch (NoClassDefFoundError e) { logger.warn("JNA not found. Native methods will be disabled."); - jnaAvailable = false; } catch (UnsatisfiedLinkError e) { - logger.warn("JNA link failure, one or more native method will be unavailable."); - logger.error("JNA link failure details: {}", e.getMessage()); + logger.error("Failed to link the C library against JNA. Native methods will be unavailable.", e); } catch (NoSuchMethodError e) { logger.warn("Obsolete version of JNA present; unable to register C library. Upgrade to JNA 3.2.7 or later"); - jnaAvailable = false; } } @@ -124,8 +122,8 @@ public class CLibraryLinux implements CLibraryWrapper return getpid(); } - public boolean jnaAvailable() + public boolean isAvailable() { - return jnaAvailable; + return available; } } diff --git a/src/java/org/apache/cassandra/utils/CLibraryWindows.java b/src/java/org/apache/cassandra/utils/NativeLibraryWindows.java similarity index 62% rename from src/java/org/apache/cassandra/utils/CLibraryWindows.java rename to src/java/org/apache/cassandra/utils/NativeLibraryWindows.java index c8b5bbb63d..0868c7ab32 100644 --- a/src/java/org/apache/cassandra/utils/CLibraryWindows.java +++ b/src/java/org/apache/cassandra/utils/NativeLibraryWindows.java @@ -21,21 +21,51 @@ package org.apache.cassandra.utils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.sun.jna.LastErrorException; +import com.sun.jna.Native; import com.sun.jna.Pointer; /** - * A CLibraryWrapper implementation for Windows. - *

- * As libc isn't available on Windows these implementations - * will obviously be a no-op, however when possible implementations - * are used that are Windows friendly that will return the same - * return value. - * @see org.apache.cassandra.utils.CLibraryWrapper - * @see CLibrary + * A {@code NativeLibraryWrapper} implementation for Windows. + *

This implementation only offer support for the {@code callGetpid} method + * using the Windows/Kernel32 library.

+ * + * @see org.apache.cassandra.utils.NativeLibraryWrapper + * @see NativeLibrary */ -public class CLibraryWindows implements CLibraryWrapper +public class NativeLibraryWindows implements NativeLibraryWrapper { - private static final Logger logger = LoggerFactory.getLogger(CLibraryWindows.class); + private static boolean available; + + private static final Logger logger = LoggerFactory.getLogger(NativeLibraryWindows.class); + + static + { + try + { + Native.register("kernel32"); + available = true; + } + catch (NoClassDefFoundError e) + { + logger.warn("JNA not found. Native methods will be disabled."); + } + catch (UnsatisfiedLinkError e) + { + logger.error("Failed to link the Windows/Kernel32 library against JNA. Native methods will be unavailable.", e); + } + catch (NoSuchMethodError e) + { + logger.warn("Obsolete version of JNA present; unable to register Windows/Kernel32 library. Upgrade to JNA 3.2.7 or later"); + } + } + + /** + * Retrieves the process identifier of the calling process (GetCurrentProcessId function). + * + * @return the process identifier of the calling process + */ + private static native long GetCurrentProcessId() throws LastErrorException; public int callMlockall(int flags) throws UnsatisfiedLinkError, RuntimeException { @@ -84,20 +114,11 @@ public class CLibraryWindows implements CLibraryWrapper */ public long callGetpid() throws UnsatisfiedLinkError, RuntimeException { - try - { - return SigarLibrary.instance.getPid(); - } - catch (Exception e) - { - logger.error("Failed to initialize or use Sigar Library", e); - } - - return -1; + return GetCurrentProcessId(); } - public boolean jnaAvailable() + public boolean isAvailable() { - return false; + return available; } } diff --git a/src/java/org/apache/cassandra/utils/CLibraryWrapper.java b/src/java/org/apache/cassandra/utils/NativeLibraryWrapper.java similarity index 87% rename from src/java/org/apache/cassandra/utils/CLibraryWrapper.java rename to src/java/org/apache/cassandra/utils/NativeLibraryWrapper.java index b97fa64afa..879ea88605 100644 --- a/src/java/org/apache/cassandra/utils/CLibraryWrapper.java +++ b/src/java/org/apache/cassandra/utils/NativeLibraryWrapper.java @@ -22,11 +22,15 @@ import com.sun.jna.Pointer; /** * An interface to implement for using OS specific native methods. - * @see CLibrary + * @see NativeLibrary */ -interface CLibraryWrapper +interface NativeLibraryWrapper { - boolean jnaAvailable(); + /** + * Checks if the library has been successfully linked. + * @return {@code true} if the library has been successfully linked, {@code false} otherwise. + */ + boolean isAvailable(); int callMlockall(int flags) throws UnsatisfiedLinkError, RuntimeException; int callMunlockall() throws UnsatisfiedLinkError, RuntimeException; diff --git a/src/java/org/apache/cassandra/utils/SyncUtil.java b/src/java/org/apache/cassandra/utils/SyncUtil.java index 4c0d89d99c..64d64cf9f8 100644 --- a/src/java/org/apache/cassandra/utils/SyncUtil.java +++ b/src/java/org/apache/cassandra/utils/SyncUtil.java @@ -176,7 +176,7 @@ public class SyncUtil if (SKIP_SYNC) return; else - CLibrary.trySync(fd); + NativeLibrary.trySync(fd); } public static void trySyncDir(File dir) @@ -184,14 +184,14 @@ public class SyncUtil if (SKIP_SYNC) return; - int directoryFD = CLibrary.tryOpenDirectory(dir.getPath()); + int directoryFD = NativeLibrary.tryOpenDirectory(dir.getPath()); try { trySync(directoryFD); } finally { - CLibrary.tryCloseFD(directoryFD); + NativeLibrary.tryCloseFD(directoryFD); } } } diff --git a/src/java/org/apache/cassandra/utils/UUIDGen.java b/src/java/org/apache/cassandra/utils/UUIDGen.java index 66649c2659..11c1895724 100644 --- a/src/java/org/apache/cassandra/utils/UUIDGen.java +++ b/src/java/org/apache/cassandra/utils/UUIDGen.java @@ -360,7 +360,7 @@ public class UUIDGen messageDigest.update(addr.getAddress()); // Identify the process on the load: we use both the PID and class loader hash. - long pid = CLibrary.getProcessID(); + long pid = NativeLibrary.getProcessID(); if (pid < 0) pid = new Random(System.currentTimeMillis()).nextLong(); FBUtilities.updateWithLong(messageDigest, pid); diff --git a/src/java/org/apache/cassandra/utils/WindowsTimer.java b/src/java/org/apache/cassandra/utils/WindowsTimer.java index 9db8559845..351751ff06 100644 --- a/src/java/org/apache/cassandra/utils/WindowsTimer.java +++ b/src/java/org/apache/cassandra/utils/WindowsTimer.java @@ -34,6 +34,10 @@ public final class WindowsTimer { Native.register("winmm"); } + catch (NoClassDefFoundError e) + { + logger.warn("JNA not found. winmm.dll cannot be registered. Performance will be negatively impacted on this node."); + } catch (Exception e) { logger.error("Failed to register winmm.dll. Performance will be negatively impacted on this node."); diff --git a/test/unit/org/apache/cassandra/utils/CLibraryTest.java b/test/unit/org/apache/cassandra/utils/NativeLibraryTest.java similarity index 89% rename from test/unit/org/apache/cassandra/utils/CLibraryTest.java rename to test/unit/org/apache/cassandra/utils/NativeLibraryTest.java index d07b1ff726..226653eb71 100644 --- a/test/unit/org/apache/cassandra/utils/CLibraryTest.java +++ b/test/unit/org/apache/cassandra/utils/NativeLibraryTest.java @@ -25,20 +25,20 @@ import org.junit.Test; import org.apache.cassandra.io.util.FileUtils; -public class CLibraryTest +public class NativeLibraryTest { @Test public void testSkipCache() { File file = FileUtils.createTempFile("testSkipCache", "1"); - CLibrary.trySkipCache(file.getPath(), 0, 0); + NativeLibrary.trySkipCache(file.getPath(), 0, 0); } @Test public void getPid() { - long pid = CLibrary.getProcessID(); + long pid = NativeLibrary.getProcessID(); Assert.assertTrue(pid > 0); } }