diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/os/AbstractNativeImpl.java b/core/src/main/java/com/datastax/oss/driver/internal/core/os/AbstractNativeImpl.java deleted file mode 100644 index 1ff4aa634c2..00000000000 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/os/AbstractNativeImpl.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 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.oss.driver.internal.core.os; - -import java.util.function.Supplier; - -public abstract class AbstractNativeImpl implements NativeImpl { - - Supplier gettimeofdaySupplier = - () -> { - return new IllegalStateException( - "Native call not available. " - + "Check isCurrentTimeMicrosAvailable() before calling this method."); - }; - - Supplier getpidSupplier = - () -> { - return new IllegalStateException( - "Native call not available. " - + "Check isGetProcessIdAvailable() before calling this method."); - }; -} diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/os/EmptyNativeImpl.java b/core/src/main/java/com/datastax/oss/driver/internal/core/os/EmptyNativeImpl.java index a8c05f3358d..8e70cd4ce8b 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/os/EmptyNativeImpl.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/os/EmptyNativeImpl.java @@ -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 gettimeofday() { + return Optional.empty(); } @Override - public int getpid() { - throw getpidSupplier.get(); + public Optional getpid() { + return Optional.empty(); } } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/os/JnrNativeImpl.java b/core/src/main/java/com/datastax/oss/driver/internal/core/os/JnrNativeImpl.java index ae6bb9ed342..93e606ea4b1 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/os/JnrNativeImpl.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/os/JnrNativeImpl.java @@ -16,6 +16,7 @@ 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; @@ -23,7 +24,7 @@ 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); @@ -34,70 +35,54 @@ public JnrNativeImpl() { this.posix = loadPosix(); } + @Override + public Optional gettimeofday() { + + return this.posix.flatMap(this::gettimeofdayImpl); + } + + @Override + public Optional getpid() { + + return this.posix.map(POSIX::getpid); + } + + @Override + public boolean available() { + return this.posix.isPresent(); + } + private Optional 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 validatePosix(POSIX posix) { - + private Optional catchAll(POSIX posix, Consumer 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 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()); } } diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/os/Native.java b/core/src/main/java/com/datastax/oss/driver/internal/core/os/Native.java index 34741c22985..73ac67fe61b 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/os/Native.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/os/Native.java @@ -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; @@ -38,18 +40,21 @@ public NativeImpl load() { } } + private static final NativeImpl IMPL = new ImplLoader().load(); + + private static final Supplier 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(); } /** @@ -57,15 +62,15 @@ public static boolean isCurrentTimeMicrosAvailable() { * {@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); } /** diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/os/NativeImpl.java b/core/src/main/java/com/datastax/oss/driver/internal/core/os/NativeImpl.java index ebd3f71956f..c8d6b44e219 100644 --- a/core/src/main/java/com/datastax/oss/driver/internal/core/os/NativeImpl.java +++ b/core/src/main/java/com/datastax/oss/driver/internal/core/os/NativeImpl.java @@ -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 gettimeofday(); - public int getpid(); + public Optional getpid(); } diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/os/JnrNativeImplTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/os/JnrNativeImplTest.java index 46d0e3962a1..aac4cf151a3 100644 --- a/core/src/test/java/com/datastax/oss/driver/internal/core/os/JnrNativeImplTest.java +++ b/core/src/test/java/com/datastax/oss/driver/internal/core/os/JnrNativeImplTest.java @@ -19,6 +19,7 @@ import java.time.Instant; import java.time.temporal.ChronoUnit; +import java.util.Optional; import org.junit.Test; /** @@ -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 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 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(); }