org.apache.hadoop.hbase.util.JVM Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of hbase-common Show documentation
Show all versions of hbase-common Show documentation
Common functionality for HBase
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.hadoop.hbase.util;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.management.ManagementFactory;
import java.lang.management.OperatingSystemMXBean;
import java.lang.management.RuntimeMXBean;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import org.apache.yetus.audience.InterfaceAudience;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.hbase.thirdparty.com.google.common.base.Splitter;
/**
* This class is a wrapper for the implementation of com.sun.management.UnixOperatingSystemMXBean It
* will decide to use the sun api or its own implementation depending on the runtime (vendor) used.
*/
@InterfaceAudience.Private
public class JVM {
private static final Logger LOG = LoggerFactory.getLogger(JVM.class);
private OperatingSystemMXBean osMbean;
private static final boolean ibmvendor =
System.getProperty("java.vendor") != null && System.getProperty("java.vendor").contains("IBM");
// At least on my systems os.name reports as "linux", not "Linux". Prefer case insensitive tests.
private static final boolean windows = System.getProperty("os.name") != null
&& System.getProperty("os.name").toLowerCase().contains("windows");
private static final boolean linux = System.getProperty("os.name") != null
&& System.getProperty("os.name").toLowerCase().contains("linux");
private static final boolean amd64 =
System.getProperty("os.arch") != null && System.getProperty("os.arch").contains("amd64");
private static final boolean aarch64 =
System.getProperty("os.arch") != null && System.getProperty("os.arch").contains("aarch64");
private static final String JVMVersion = System.getProperty("java.version");
/**
* The raw String of java specification version. "1.8" for java8, "9","10"... for Java 9, 10...
*/
private static final String JVM_SPEC_VERSION_STRING =
System.getProperty("java.specification.version");
/**
* The Integer represent of JVM_SPEC_VERSION, for the JVM version comparison. Java 8, 9, 10 ...
* will be noted as 8, 9 10 ...
*/
private static final int JVM_SPEC_VERSION = JVM_SPEC_VERSION_STRING.contains(".")
? (int) (Float.parseFloat(JVM_SPEC_VERSION_STRING) * 10 % 10)
: Integer.parseInt(JVM_SPEC_VERSION_STRING);
/**
* Constructor. Get the running Operating System instance
*/
public JVM() {
this.osMbean = ManagementFactory.getOperatingSystemMXBean();
}
/**
* Check if the OS is unix.
* @return whether this is unix or not.
*/
public static boolean isUnix() {
if (windows) {
return false;
}
return (ibmvendor ? linux : true);
}
/**
* Check if the OS is linux.
* @return whether this is linux or not.
*/
public static boolean isLinux() {
return linux;
}
/**
* Check if the arch is amd64;
* @return whether this is amd64 or not.
*/
public static boolean isAmd64() {
return amd64;
}
/**
* Check if the arch is aarch64;
* @return whether this is aarch64 or not.
*/
public static boolean isAarch64() {
return aarch64;
}
/**
* Check if the finish() method of GZIPOutputStream is broken
* @return whether GZIPOutputStream.finish() is broken.
*/
public static boolean isGZIPOutputStreamFinishBroken() {
return ibmvendor && JVMVersion.contains("1.6.0");
}
public static int getJVMSpecVersion() {
return JVM_SPEC_VERSION;
}
/**
* Load the implementation of UnixOperatingSystemMXBean for Oracle jvm and runs the desired
* method.
* @param mBeanMethodName : method to run from the interface UnixOperatingSystemMXBean
* @return the method result
*/
private Long runUnixMXBeanMethod(String mBeanMethodName) {
Object unixos;
Class> classRef;
Method mBeanMethod;
try {
classRef = Class.forName("com.sun.management.UnixOperatingSystemMXBean");
if (classRef.isInstance(osMbean)) {
mBeanMethod = classRef.getMethod(mBeanMethodName);
unixos = classRef.cast(osMbean);
return (Long) mBeanMethod.invoke(unixos);
}
} catch (Exception e) {
LOG.warn(
"Not able to load class or method for" + " com.sun.management.UnixOperatingSystemMXBean.",
e);
}
return null;
}
/**
* Get the number of opened filed descriptor for the runtime jvm. If Oracle java, it will use the
* com.sun.management interfaces. Otherwise, this methods implements it (linux only).
* @return number of open file descriptors for the jvm
*/
public long getOpenFileDescriptorCount() {
Long ofdc;
if (!ibmvendor) {
ofdc = runUnixMXBeanMethod("getOpenFileDescriptorCount");
return (ofdc != null ? ofdc : -1);
}
InputStream inputStream = null;
InputStreamReader inputStreamReader = null;
BufferedReader bufferedReader = null;
try {
// need to get the PID number of the process first
RuntimeMXBean rtmbean = ManagementFactory.getRuntimeMXBean();
String rtname = rtmbean.getName();
Iterator pidhost = Splitter.on('@').split(rtname).iterator();
// using linux bash commands to retrieve info
Process p = Runtime.getRuntime()
.exec(new String[] { "bash", "-c", "ls /proc/" + pidhost.next() + "/fdinfo | wc -l" });
inputStream = p.getInputStream();
inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
bufferedReader = new BufferedReader(inputStreamReader);
String openFileDesCount;
if ((openFileDesCount = bufferedReader.readLine()) != null) {
return Long.parseLong(openFileDesCount);
}
} catch (IOException ie) {
LOG.warn("Not able to get the number of open file descriptors", ie);
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException e) {
LOG.warn("Not able to close the BufferedReader", e);
}
}
if (inputStreamReader != null) {
try {
inputStreamReader.close();
} catch (IOException e) {
LOG.warn("Not able to close the InputStreamReader", e);
}
}
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
LOG.warn("Not able to close the InputStream", e);
}
}
}
return -1;
}
/**
* Get the system load average
* @see java.lang.management.OperatingSystemMXBean#getSystemLoadAverage
*/
public double getSystemLoadAverage() {
return osMbean.getSystemLoadAverage();
}
/**
* Return the physical free memory (not the JVM one, as it's not very useful as it depends on the
* GC), but the one from the OS as it allows a little bit more to guess if the machine is
* overloaded or not).
*/
public long getFreeMemory() {
if (ibmvendor) {
return 0;
}
Long r = runUnixMXBeanMethod("getFreePhysicalMemorySize");
return (r != null ? r : -1);
}
/**
* Workaround to get the current number of process running. Approach is the one described here:
* http://stackoverflow.com/questions/54686/how-to-get-a-list-of-current-open-windows-process-with-java
*/
@edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "RV_DONT_JUST_NULL_CHECK_READLINE",
justification = "used by testing")
public int getNumberOfRunningProcess() {
if (!isUnix()) {
return 0;
}
InputStream inputStream = null;
InputStreamReader inputStreamReader = null;
BufferedReader bufferedReader = null;
try {
int count = 0;
Process p = Runtime.getRuntime().exec("ps -e");
inputStream = p.getInputStream();
inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
bufferedReader = new BufferedReader(inputStreamReader);
while (bufferedReader.readLine() != null) {
count++;
}
return count - 1; // -1 because there is a headline
} catch (IOException e) {
return -1;
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException e) {
LOG.warn("Not able to close the BufferedReader", e);
}
}
if (inputStreamReader != null) {
try {
inputStreamReader.close();
} catch (IOException e) {
LOG.warn("Not able to close the InputStreamReader", e);
}
}
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
LOG.warn("Not able to close the InputStream", e);
}
}
}
}
/**
* Get the number of the maximum file descriptors the system can use. If Oracle java, it will use
* the com.sun.management interfaces. Otherwise, this methods implements it (linux only).
* @return max number of file descriptors the operating system can use.
*/
public long getMaxFileDescriptorCount() {
Long mfdc;
if (!ibmvendor) {
mfdc = runUnixMXBeanMethod("getMaxFileDescriptorCount");
return (mfdc != null ? mfdc : -1);
}
InputStream in = null;
BufferedReader output = null;
try {
// using linux bash commands to retrieve info
Process p = Runtime.getRuntime().exec(new String[] { "bash", "-c", "ulimit -n" });
in = p.getInputStream();
output = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8));
String maxFileDesCount;
if ((maxFileDesCount = output.readLine()) != null) {
return Long.parseLong(maxFileDesCount);
}
} catch (IOException ie) {
LOG.warn("Not able to get the max number of file descriptors", ie);
} finally {
if (output != null) {
try {
output.close();
} catch (IOException e) {
LOG.warn("Not able to close the reader", e);
}
}
if (in != null) {
try {
in.close();
} catch (IOException e) {
LOG.warn("Not able to close the InputStream", e);
}
}
}
return -1;
}
}