All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.datastax.driver.core.Native Maven / Gradle / Ivy

/*
 * Copyright DataStax, Inc.
 *
 * This software can be used solely with DataStax Enterprise. Please consult the license at
 * http://www.datastax.com/terms/datastax-dse-driver-license-terms
 */
package com.datastax.driver.core;

import java.lang.reflect.Method;
import jnr.ffi.LibraryLoader;
import jnr.ffi.Platform;
import jnr.ffi.Pointer;
import jnr.ffi.Runtime;
import jnr.ffi.Struct;
import jnr.ffi.annotations.Out;
import jnr.ffi.annotations.Transient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Helper class to deal with native system calls through the JNR library.
 *
 * 

The driver can benefit from native system calls to improve its performance and accuracy in * some situations. * *

Currently, the following features may be used by the driver when available: * *

    *
  1. {@link #currentTimeMicros()}: thanks to a system call to {@code gettimeofday()}, the driver * is able to generate timestamps with true microsecond precision (see {@link * AtomicMonotonicTimestampGenerator} or {@link ThreadLocalMonotonicTimestampGenerator} for * more information); *
  2. {@link #processId()}: thanks to a system call to {@code getpid()}, the driver has access to * the JVM's process ID it is running under – which makes time-based UUID generation easier * and more reliable (see {@link com.datastax.driver.core.utils.UUIDs UUIDs} for more * information). *
  3. {@link #getCPU()}: thanks to {@link Platform#getCPU()}, the driver is able to report the * current processor architecture the JVM is running on. *
* *

The availability of the aforementioned system calls depends on the underlying operation * system's capabilities. For instance, {@code gettimeofday()} is not available under Windows * systems. You can check if any of the system calls exposed through this class is available by * calling {@link #isGettimeofdayAvailable()} or {@link #isGetpidAvailable()} or {@link * #isPlatformAvailable()}. The method {@link #getCPU()} should always be available, unless the * jnr-ffi dependency itself is not present on the classpath. * *

Note: This class is public because it needs to be accessible from other packages of the Java * driver, but it is not meant to be used directly by client code. * * @see JNR library on Github */ public final class Native { private static final Logger LOGGER = LoggerFactory.getLogger(Native.class); private static class LibCLoader { /** * Timeval struct. * * @see GETTIMEOFDAY(2) */ static class Timeval extends Struct { public final time_t tv_sec = new time_t(); public final Unsigned32 tv_usec = new Unsigned32(); public Timeval(Runtime runtime) { super(runtime); } } /** Interface for LIBC calls through JNR. Note that this interface must be declared public. */ public interface LibC { /** * JNR call to {@code gettimeofday}. * * @param tv Timeval struct * @param unused Timezone struct (unused) * @return 0 for success, or -1 for failure * @see GETTIMEOFDAY(2) */ int gettimeofday(@Out @Transient Timeval tv, Pointer unused); } private static final LibC LIB_C; private static final Runtime LIB_C_RUNTIME; private static final boolean GETTIMEOFDAY_AVAILABLE; static { LibC libc; Runtime runtime = null; try { libc = LibraryLoader.create(LibC.class).load("c"); runtime = Runtime.getRuntime(libc); } catch (Throwable t) { libc = null; // dereference proxy to library if runtime could not be loaded if (LOGGER.isDebugEnabled()) LOGGER.debug( "Could not load JNR C Library, native system calls through this library will not be available", t); else LOGGER.info( "Could not load JNR C Library, native system calls through this library will not be available " + "(set this logger level to DEBUG to see the full stack trace)."); } LIB_C = libc; LIB_C_RUNTIME = runtime; boolean gettimeofday = false; if (LIB_C_RUNTIME != null) { try { gettimeofday = LIB_C.gettimeofday(new Timeval(LIB_C_RUNTIME), null) == 0; } catch (Throwable t) { if (LOGGER.isDebugEnabled()) LOGGER.debug("Native calls to gettimeofday() not available on this system.", t); else LOGGER.info( "Native calls to gettimeofday() not available on this system " + "(set this logger level to DEBUG to see the full stack trace)."); } } GETTIMEOFDAY_AVAILABLE = gettimeofday; } } private static class PosixLoader { public static final jnr.posix.POSIX POSIX; private static final boolean GETPID_AVAILABLE; static { jnr.posix.POSIX posix; try { // use reflection below to get the classloader a chance to load this class Class posixHandler = Class.forName("jnr.posix.POSIXHandler"); Class defaultPosixHandler = Class.forName("jnr.posix.util.DefaultPOSIXHandler"); Class posixFactory = Class.forName("jnr.posix.POSIXFactory"); Method getPOSIX = posixFactory.getMethod("getPOSIX", posixHandler, Boolean.TYPE); posix = (jnr.posix.POSIX) getPOSIX.invoke(null, defaultPosixHandler.newInstance(), true); } catch (Throwable t) { posix = null; if (LOGGER.isDebugEnabled()) LOGGER.debug( "Could not load JNR POSIX Library, native system calls through this library will not be available.", t); else LOGGER.info( "Could not load JNR POSIX Library, native system calls through this library will not be available " + "(set this logger level to DEBUG to see the full stack trace)."); } POSIX = posix; boolean getpid = false; if (POSIX != null) { try { POSIX.getpid(); getpid = true; } catch (Throwable t) { if (LOGGER.isDebugEnabled()) LOGGER.debug("Native calls to getpid() not available on this system.", t); else LOGGER.info( "Native calls to getpid() not available on this system " + "(set this logger level to DEBUG to see the full stack trace)."); } } GETPID_AVAILABLE = getpid; } } private static class PlatformLoader { private static final Platform PLATFORM; static { Platform platform; try { Class platformClass = Class.forName("jnr.ffi.Platform"); Method getNativePlatform = platformClass.getMethod("getNativePlatform"); platform = (Platform) getNativePlatform.invoke(null); } catch (Throwable t) { platform = null; if (LOGGER.isDebugEnabled()) LOGGER.debug( "Could not load jnr.ffi.Platform class, this class will not be available.", t); else LOGGER.info( "Could not load jnr.ffi.Platform class, this class will not be available " + "(set this logger level to DEBUG to see the full stack trace)."); } PLATFORM = platform; } } /** * Returns {@code true} if JNR C library is loaded and a call to {@code gettimeofday} is possible * through this library on this system, and {@code false} otherwise. * * @return {@code true} if JNR C library is loaded and a call to {@code gettimeofday} is possible. */ public static boolean isGettimeofdayAvailable() { try { return LibCLoader.GETTIMEOFDAY_AVAILABLE; } catch (NoClassDefFoundError e) { return false; } } /** * Returns {@code true} if JNR POSIX library is loaded and a call to {@code getpid} is possible * through this library on this system, and {@code false} otherwise. * * @return {@code true} if JNR POSIX library is loaded and a call to {@code getpid} is possible. */ public static boolean isGetpidAvailable() { try { return PosixLoader.GETPID_AVAILABLE; } catch (NoClassDefFoundError e) { return false; } } /** * Returns {@code true} if JNR {@link Platform} class is loaded, and {@code false} otherwise. * * @return {@code true} if JNR {@link Platform} class is loaded. */ public static boolean isPlatformAvailable() { try { return PlatformLoader.PLATFORM != null; } catch (NoClassDefFoundError e) { return false; } } /** * Returns the current timestamp with microsecond precision via a system call to {@code * gettimeofday}, through JNR C library. * * @return the current timestamp with microsecond precision. * @throws UnsupportedOperationException if JNR C library is not loaded or {@code gettimeofday} is * not available. * @throws IllegalStateException if the call to {@code gettimeofday} did not complete with return * code 0. */ public static long currentTimeMicros() { if (!isGettimeofdayAvailable()) throw new UnsupportedOperationException( "JNR C library not loaded or gettimeofday not available"); LibCLoader.Timeval tv = new LibCLoader.Timeval(LibCLoader.LIB_C_RUNTIME); int res = LibCLoader.LIB_C.gettimeofday(tv, null); if (res != 0) throw new IllegalStateException("Call to gettimeofday failed with result " + res); return tv.tv_sec.get() * 1000000 + tv.tv_usec.get(); } /** * Returns the JVM's process identifier (PID) via a system call to {@code getpid}. * * @return the JVM's process identifier (PID). * @throws UnsupportedOperationException if JNR POSIX library is not loaded or {@code getpid} is * not available. */ public static int processId() { if (!isGetpidAvailable()) throw new UnsupportedOperationException( "JNR POSIX library not loaded or getpid not available"); return PosixLoader.POSIX.getpid(); } /** * Returns the current processor architecture the JVM is running on, as reported by {@link * Platform#getCPU()}. * * @return the current processor architecture. * @throws UnsupportedOperationException if JNR Platform library is not loaded. */ public static String getCPU() { if (!isPlatformAvailable()) throw new UnsupportedOperationException("JNR Platform class not loaded"); return PlatformLoader.PLATFORM.getCPU().toString(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy