/* * 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.facebook.presto.server; import com.google.common.base.StandardSystemProperty; import io.airlift.slice.Slice; import io.airlift.slice.Slices; import org.joda.time.DateTime; import javax.management.MBeanServer; import javax.management.ObjectName; import java.lang.management.GarbageCollectorMXBean; import java.lang.management.ManagementFactory; import java.nio.ByteOrder; import java.util.List; import java.util.Locale; import java.util.OptionalLong; import static com.google.common.collect.ImmutableList.toImmutableList; import static java.lang.management.ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME; final class PrestoSystemRequirements { private static final int MIN_FILE_DESCRIPTORS = 4096; private static final int RECOMMENDED_FILE_DESCRIPTORS = 8192; private PrestoSystemRequirements() {} public static void verifyJvmRequirements() { String vendor = StandardSystemProperty.JAVA_VENDOR.value(); if (!"Oracle Corporation".equals(vendor)) { failRequirement("Presto requires an Oracle or OpenJDK JVM (found %s)", vendor); } verifyJavaVersion(); String dataModel = System.getProperty("sun.arch.data.model"); if (!"64".equals(dataModel)) { failRequirement("Presto requires a 64-bit JVM (found %s)", dataModel); } String osName = StandardSystemProperty.OS_NAME.value(); String osArch = StandardSystemProperty.OS_ARCH.value(); if ("Linux".equals(osName)) { if (!"amd64".equals(osArch)) { failRequirement("Presto requires x86-64 or amd64 on Linux (found %s)", osArch); } } else if ("Mac OS X".equals(osName)) { if (!"x86_64".equals(osArch)) { failRequirement("Presto requires x86_64 on Mac OS X (found %s)", osArch); } } else { failRequirement("Presto requires Linux or Mac OS X (found %s)", osName); } if (!ByteOrder.nativeOrder().equals(ByteOrder.LITTLE_ENDIAN)) { failRequirement("Presto requires a little endian platform (found %s)", ByteOrder.nativeOrder()); } verifyUsingG1Gc(); verifyFileDescriptor(); verifySlice(); } private static void verifyJavaVersion() { String javaVersion = StandardSystemProperty.JAVA_VERSION.value(); if (javaVersion == null) { failRequirement("Java version not defined"); } JavaVersion version = JavaVersion.parse(javaVersion); if (version.getMajor() == 8 && version.getUpdate().isPresent() && version.getUpdate().getAsInt() >= 92) { return; } if (version.getMajor() == 9) { return; } failRequirement("Presto requires Java 8u92+ (found %s)", javaVersion); } private static void verifyUsingG1Gc() { try { List<String> garbageCollectors = ManagementFactory.getGarbageCollectorMXBeans().stream() .map(GarbageCollectorMXBean::getName) .collect(toImmutableList()); if (garbageCollectors.stream().noneMatch(name -> name.toUpperCase(Locale.US).startsWith("G1 "))) { warnRequirement("Current garbage collectors are %s. Presto recommends the G1 garbage collector.", garbageCollectors); } } catch (RuntimeException e) { // This should never happen since we have verified the OS and JVM above failRequirement("Cannot read garbage collector information: %s", e); } } private static void verifyFileDescriptor() { OptionalLong maxFileDescriptorCount = getMaxFileDescriptorCount(); if (!maxFileDescriptorCount.isPresent()) { // This should never happen since we have verified the OS and JVM above failRequirement("Cannot read OS file descriptor limit"); } if (maxFileDescriptorCount.getAsLong() < MIN_FILE_DESCRIPTORS) { failRequirement("Presto requires at least %s file descriptors (found %s)", MIN_FILE_DESCRIPTORS, maxFileDescriptorCount.getAsLong()); } if (maxFileDescriptorCount.getAsLong() < RECOMMENDED_FILE_DESCRIPTORS) { warnRequirement("Current OS file descriptor limit is %s. Presto recommends at least %s", maxFileDescriptorCount.getAsLong(), RECOMMENDED_FILE_DESCRIPTORS); } } private static OptionalLong getMaxFileDescriptorCount() { try { MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer(); Object maxFileDescriptorCount = mbeanServer.getAttribute(ObjectName.getInstance(OPERATING_SYSTEM_MXBEAN_NAME), "MaxFileDescriptorCount"); return OptionalLong.of(((Number) maxFileDescriptorCount).longValue()); } catch (Exception e) { return OptionalLong.empty(); } } private static void verifySlice() { Slice slice = Slices.wrappedBuffer(new byte[5]); slice.setByte(4, 0xDE); slice.setByte(3, 0xAD); slice.setByte(2, 0xBE); slice.setByte(1, 0xEF); if (slice.getInt(1) != 0xDEADBEEF) { failRequirement("Slice library produced an unexpected result"); } } /** * Perform a sanity check to make sure that the year is reasonably current, to guard against * issues in third party libraries. */ public static void verifySystemTimeIsReasonable() { int currentYear = DateTime.now().year().get(); if (currentYear < 2015) { failRequirement("Presto requires the system time to be current (found year %s)", currentYear); } } private static void failRequirement(String format, Object... args) { System.err.println(String.format(format, args)); System.exit(100); } private static void warnRequirement(String format, Object... args) { System.err.println("WARNING: " + String.format(format, args)); } }