Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,23 @@
*/
package com.datastax.oss.driver.internal.core.os;

import java.util.Optional;

/** A no-op NativeImpl implementation; useful if we can't load one of the others */
public class EmptyNativeImpl extends AbstractNativeImpl {
public class EmptyNativeImpl implements NativeImpl {

@Override
public boolean gettimeofdayAvailable() {
public boolean available() {
return false;
}

@Override
public long gettimeofday() {
throw gettimeofdaySupplier.get();
}

@Override
public boolean getpidAvailable() {
return false;
public Optional<Long> gettimeofday() {
return Optional.empty();
}

@Override
public int getpid() {
throw getpidSupplier.get();
public Optional<Integer> getpid() {
return Optional.empty();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,15 @@
package com.datastax.oss.driver.internal.core.os;

import java.util.Optional;
import java.util.function.Consumer;
import jnr.posix.POSIX;
import jnr.posix.POSIXFactory;
import jnr.posix.Timeval;
import jnr.posix.util.DefaultPOSIXHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class JnrNativeImpl extends AbstractNativeImpl {
public class JnrNativeImpl implements NativeImpl {

private static final Logger LOG = LoggerFactory.getLogger(JnrNativeImpl.class);

Expand All @@ -34,70 +35,54 @@ public JnrNativeImpl() {
this.posix = loadPosix();
}

@Override
public Optional<Long> gettimeofday() {

return this.posix.flatMap(this::gettimeofdayImpl);
}

@Override
public Optional<Integer> getpid() {

return this.posix.map(POSIX::getpid);
}

@Override
public boolean available() {
return this.posix.isPresent();
}

private Optional<POSIX> loadPosix() {

try {
return Optional.of(POSIXFactory.getPOSIX(new DefaultPOSIXHandler(), true))
.flatMap(this::validatePosix);
.flatMap(p -> catchAll(p, posix -> posix.getpid(), "Error calling getpid()"))
.flatMap(p -> catchAll(p, this::gettimeofdayImpl, "Error calling gettimeofday()"));
} catch (Throwable t) {
LOG.debug("Error loading POSIX", t);
return Optional.empty();
}
}

private Optional<POSIX> validatePosix(POSIX posix) {

private Optional<POSIX> catchAll(POSIX posix, Consumer<POSIX> fn, String debugStr) {
try {

posix.getpid();
fn.accept(posix);
return Optional.of(posix);
} catch (Throwable t) {

LOG.debug("Error calling getpid()", t);
LOG.debug(debugStr, t);
return Optional.empty();
}

try {

Timeval tv = posix.allocateTimeval();
int rv = posix.gettimeofday(tv);
if (rv != 0) {

LOG.debug("Expected getitimeofday() to return zero, observed {}", rv);
return Optional.empty();
}
} catch (Throwable t) {

LOG.debug("Error calling gettimeofday()", t);
return Optional.empty();
}

return Optional.of(posix);
}

@Override
public boolean gettimeofdayAvailable() {
return posix.isPresent();
}

@Override
public long gettimeofday() {
private Optional<Long> gettimeofdayImpl(POSIX posix) {

Timeval tv = this.posix.map(POSIX::allocateTimeval).orElseThrow(gettimeofdaySupplier);
int rv = this.posix.map(p -> p.gettimeofday(tv)).orElseThrow(gettimeofdaySupplier);
Timeval tv = posix.allocateTimeval();
int rv = posix.gettimeofday(tv);
if (rv != 0) {
throw new IllegalStateException(
"Expected 0 return value from gettimeofday(), observed " + rv);
LOG.debug("Expected 0 return value from gettimeofday(), observed " + rv);
return Optional.empty();
}
return tv.sec() * 1_000_000 + tv.usec();
}

@Override
public boolean getpidAvailable() {
return posix.isPresent();
}

@Override
public int getpid() {
return this.posix.map(POSIX::getpid).orElseThrow(getpidSupplier);
return Optional.of(tv.sec() * 1_000_000 + tv.usec());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
*/
package com.datastax.oss.driver.internal.core.os;

import com.datastax.oss.driver.shaded.guava.common.base.Suppliers;
import java.util.Locale;
import java.util.function.Supplier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -38,34 +40,37 @@ public NativeImpl load() {
}
}

private static final NativeImpl IMPL = new ImplLoader().load();

private static final Supplier<IllegalStateException> exceptionSupplier =
Suppliers.ofInstance(new IllegalStateException("Native call failed or was not available"));

/* Copied from equivalent op in jnr.ffi.Platform. We have to have this here as it has to be defined
* before its (multiple) uses in determineCpu() */
private static final Locale LOCALE = Locale.ENGLISH;

private static final NativeImpl IMPL = new ImplLoader().load();

@SuppressWarnings("VariableNameSameAsType")
private static final Cpu CPU = determineCpu();

/** Whether {@link Native#currentTimeMicros()} is available on this system. */
public static boolean isCurrentTimeMicrosAvailable() {
return IMPL.gettimeofdayAvailable();
return IMPL.available();
}

/**
* The current time in microseconds, as returned by libc.gettimeofday(); can only be used if
* {@link #isCurrentTimeMicrosAvailable()} is true.
*/
public static long currentTimeMicros() {
return IMPL.gettimeofday();
return IMPL.gettimeofday().orElseThrow(exceptionSupplier);
}

public static boolean isGetProcessIdAvailable() {
return IMPL.getpidAvailable();
return IMPL.available();
}

public static int getProcessId() {
return IMPL.getpid();
return IMPL.getpid().orElseThrow(exceptionSupplier);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@
*/
package com.datastax.oss.driver.internal.core.os;

public interface NativeImpl {
import java.util.Optional;

public boolean gettimeofdayAvailable();
public interface NativeImpl {

public long gettimeofday();
/* Maintained to allow Native.isXAvailable() functionality without trying to make a native call if
* the underlying support _is_ available. */
public boolean available();

public boolean getpidAvailable();
public Optional<Long> gettimeofday();
Comment thread
adutra marked this conversation as resolved.

public int getpid();
public Optional<Integer> getpid();
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Optional;
import org.junit.Test;

/**
Expand All @@ -27,22 +28,30 @@
*/
public class JnrNativeImplTest {

@Test
public void should_be_available() {

NativeImpl impl = new JnrNativeImpl();
assertThat(impl.available()).isTrue();
}

@Test
public void should_support_getpid() {
NativeImpl impl = new JnrNativeImpl();
assertThat(impl.getpidAvailable()).isTrue();
assertThat(impl.getpid()).isGreaterThan(1);
Optional<Integer> val = impl.getpid();
assertThat(val).isNotEmpty();
assertThat(val.get()).isGreaterThan(1);
}

@Test
public void should_support_gettimeofday() {
NativeImpl impl = new JnrNativeImpl();
assertThat(impl.gettimeofdayAvailable()).isTrue();
long rv = impl.gettimeofday();
assertThat(rv).isGreaterThan(0);
Optional<Long> val = impl.gettimeofday();
assertThat(val).isNotEmpty();
assertThat(val.get()).isGreaterThan(0);

Instant now = Instant.now();
Instant rvInstant = Instant.EPOCH.plus(rv, ChronoUnit.MICROS);
Instant rvInstant = Instant.EPOCH.plus(val.get(), ChronoUnit.MICROS);
assertThat(rvInstant.isAfter(now.minusSeconds(1))).isTrue();
assertThat(rvInstant.isBefore(now.plusSeconds(1))).isTrue();
}
Expand Down