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

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

There is a newer version: 3.6.0-1
Show newest version
/*
 *      Copyright (C) 2012-2015 DataStax Inc.
 *
 *   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 com.datastax.driver.core;

import jnr.ffi.LibraryLoader;
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;

import java.lang.reflect.Method;

/**
 * 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. *
  3. {@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).
  4. *
*

* 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()}. *

* 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; } } /** * 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 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(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy