blob: 3e1e7df9436cae11aa4102df7325ead8d94ff75a [file] [log] [blame]
// 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.impala.common;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.management.GarbageCollectorMXBean;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryPoolMXBean;
import java.lang.management.MemoryUsage;
import java.lang.management.RuntimeMXBean;
import java.lang.management.ThreadMXBean;
import java.lang.management.ThreadInfo;
import java.util.ArrayList;
import java.util.Map;
import org.apache.impala.thrift.TGetJMXJsonResponse;
import org.apache.impala.util.JMXJsonUtil;
import org.apache.thrift.TBase;
import org.apache.thrift.TSerializer;
import org.apache.thrift.TDeserializer;
import org.apache.thrift.TException;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TProtocolFactory;
import com.google.common.base.Joiner;
import org.apache.impala.thrift.TGetJvmMemoryMetricsResponse;
import org.apache.impala.thrift.TGetJvmThreadsInfoRequest;
import org.apache.impala.thrift.TGetJvmThreadsInfoResponse;
import org.apache.impala.thrift.TJvmMemoryPool;
import org.apache.impala.thrift.TJvmThreadInfo;
import org.apache.impala.util.JvmPauseMonitor;
import org.apache.log4j.Logger;
/**
* Utility class with methods intended for JNI clients
*/
public class JniUtil {
private final static TBinaryProtocol.Factory protocolFactory_ =
new TBinaryProtocol.Factory();
private static final Logger LOG = Logger.getLogger(JniUtil.class);
/**
* Initializes the JvmPauseMonitor instance.
*/
public static void initPauseMonitor(long deadlockCheckIntervalS) {
JvmPauseMonitor.INSTANCE.initPauseMonitor(deadlockCheckIntervalS);
}
/**
* Returns a formatted string containing the simple exception name and the
* exception message without the full stack trace. Includes the
* the chain of causes each in a separate line.
*/
public static String throwableToString(Throwable t) {
StringWriter output = new StringWriter();
output.write(String.format("%s: %s", t.getClass().getSimpleName(),
t.getMessage()));
// Follow the chain of exception causes and print them as well.
Throwable cause = t;
while ((cause = cause.getCause()) != null) {
output.write(String.format("\nCAUSED BY: %s: %s",
cause.getClass().getSimpleName(), cause.getMessage()));
}
return output.toString();
}
/**
* Returns the stack trace of the Throwable object.
*/
public static String throwableToStackTrace(Throwable t) {
Writer output = new StringWriter();
t.printStackTrace(new PrintWriter(output));
return output.toString();
}
/**
* Serializes input into a byte[] using the default protocol factory.
*/
public static <T extends TBase<?, ?>>
byte[] serializeToThrift(T input) throws ImpalaException {
TSerializer serializer = new TSerializer(protocolFactory_);
try {
return serializer.serialize(input);
} catch (TException e) {
throw new InternalException(e.getMessage());
}
}
/**
* Serializes input into a byte[] using a given protocol factory.
*/
public static <T extends TBase<?, ?>, F extends TProtocolFactory>
byte[] serializeToThrift(T input, F protocolFactory) throws ImpalaException {
TSerializer serializer = new TSerializer(protocolFactory);
try {
return serializer.serialize(input);
} catch (TException e) {
throw new InternalException(e.getMessage());
}
}
public static <T extends TBase<?, ?>>
void deserializeThrift(T result, byte[] thriftData) throws ImpalaException {
deserializeThrift(protocolFactory_, result, thriftData);
}
/**
* Deserialize a serialized form of a Thrift data structure to its object form.
*/
public static <T extends TBase<?, ?>, F extends TProtocolFactory>
void deserializeThrift(F protocolFactory, T result, byte[] thriftData)
throws ImpalaException {
// TODO: avoid creating deserializer for each query?
TDeserializer deserializer = new TDeserializer(protocolFactory);
try {
deserializer.deserialize(result, thriftData);
} catch (TException e) {
throw new InternalException(e.getMessage());
}
}
/**
* Collect the JVM's memory statistics into a thrift structure for translation into
* Impala metrics by the backend. A synthetic 'total' memory pool is included with
* aggregate statistics for all real pools. Metrics for the JvmPauseMonitor
* and Garbage Collection are also included.
*/
public static byte[] getJvmMemoryMetrics() throws ImpalaException {
TGetJvmMemoryMetricsResponse jvmMetrics = new TGetJvmMemoryMetricsResponse();
jvmMetrics.setMemory_pools(new ArrayList<TJvmMemoryPool>());
TJvmMemoryPool totalUsage = new TJvmMemoryPool();
totalUsage.setName("total");
jvmMetrics.getMemory_pools().add(totalUsage);
for (MemoryPoolMXBean memBean: ManagementFactory.getMemoryPoolMXBeans()) {
TJvmMemoryPool usage = new TJvmMemoryPool();
MemoryUsage beanUsage = memBean.getUsage();
usage.setCommitted(beanUsage.getCommitted());
usage.setInit(beanUsage.getInit());
usage.setMax(beanUsage.getMax());
usage.setUsed(beanUsage.getUsed());
usage.setName(memBean.getName());
totalUsage.committed += beanUsage.getCommitted();
totalUsage.init += beanUsage.getInit();
totalUsage.max += beanUsage.getMax();
totalUsage.used += beanUsage.getUsed();
MemoryUsage peakUsage = memBean.getPeakUsage();
usage.setPeak_committed(peakUsage.getCommitted());
usage.setPeak_init(peakUsage.getInit());
usage.setPeak_max(peakUsage.getMax());
usage.setPeak_used(peakUsage.getUsed());
totalUsage.peak_committed += peakUsage.getCommitted();
totalUsage.peak_init += peakUsage.getInit();
totalUsage.peak_max += peakUsage.getMax();
totalUsage.peak_used += peakUsage.getUsed();
jvmMetrics.getMemory_pools().add(usage);
}
// Populate heap usage
MemoryMXBean mBean = ManagementFactory.getMemoryMXBean();
TJvmMemoryPool heap = new TJvmMemoryPool();
MemoryUsage heapUsage = mBean.getHeapMemoryUsage();
heap.setCommitted(heapUsage.getCommitted());
heap.setInit(heapUsage.getInit());
heap.setMax(heapUsage.getMax());
heap.setUsed(heapUsage.getUsed());
heap.setName("heap");
heap.setPeak_committed(0);
heap.setPeak_init(0);
heap.setPeak_max(0);
heap.setPeak_used(0);
jvmMetrics.getMemory_pools().add(heap);
// Populate non-heap usage
TJvmMemoryPool nonHeap = new TJvmMemoryPool();
MemoryUsage nonHeapUsage = mBean.getNonHeapMemoryUsage();
nonHeap.setCommitted(nonHeapUsage.getCommitted());
nonHeap.setInit(nonHeapUsage.getInit());
nonHeap.setMax(nonHeapUsage.getMax());
nonHeap.setUsed(nonHeapUsage.getUsed());
nonHeap.setName("non-heap");
nonHeap.setPeak_committed(0);
nonHeap.setPeak_init(0);
nonHeap.setPeak_max(0);
nonHeap.setPeak_used(0);
jvmMetrics.getMemory_pools().add(nonHeap);
// Populate JvmPauseMonitor metrics
jvmMetrics.setGc_num_warn_threshold_exceeded(
JvmPauseMonitor.INSTANCE.getNumGcWarnThresholdExceeded());
jvmMetrics.setGc_num_info_threshold_exceeded(
JvmPauseMonitor.INSTANCE.getNumGcInfoThresholdExceeded());
jvmMetrics.setGc_total_extra_sleep_time_millis(
JvmPauseMonitor.INSTANCE.getTotalGcExtraSleepTime());
// And Garbage Collector metrics
long gcCount = 0;
long gcTimeMillis = 0;
for (GarbageCollectorMXBean bean : ManagementFactory.getGarbageCollectorMXBeans()) {
gcCount += bean.getCollectionCount();
gcTimeMillis += bean.getCollectionTime();
}
jvmMetrics.setGc_count(gcCount);
jvmMetrics.setGc_time_millis(gcTimeMillis);
return serializeToThrift(jvmMetrics, protocolFactory_);
}
/**
* Get information about the live JVM threads.
*/
public static byte[] getJvmThreadsInfo(byte[] argument) throws ImpalaException {
TGetJvmThreadsInfoRequest request = new TGetJvmThreadsInfoRequest();
JniUtil.deserializeThrift(protocolFactory_, request, argument);
TGetJvmThreadsInfoResponse response = new TGetJvmThreadsInfoResponse();
ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
response.setTotal_thread_count(threadBean.getThreadCount());
response.setDaemon_thread_count(threadBean.getDaemonThreadCount());
response.setPeak_thread_count(threadBean.getPeakThreadCount());
if (request.get_complete_info) {
for (ThreadInfo threadInfo: threadBean.dumpAllThreads(true, true)) {
TJvmThreadInfo tThreadInfo = new TJvmThreadInfo();
long id = threadInfo.getThreadId();
tThreadInfo.setSummary(threadInfo.toString());
tThreadInfo.setCpu_time_in_ns(threadBean.getThreadCpuTime(id));
tThreadInfo.setUser_time_in_ns(threadBean.getThreadUserTime(id));
tThreadInfo.setBlocked_count(threadInfo.getBlockedCount());
tThreadInfo.setBlocked_time_in_ms(threadInfo.getBlockedTime());
tThreadInfo.setIs_in_native(threadInfo.isInNative());
response.addToThreads(tThreadInfo);
}
}
return serializeToThrift(response, protocolFactory_);
}
public static byte[] getJMXJson() throws ImpalaException {
TGetJMXJsonResponse response = new TGetJMXJsonResponse(JMXJsonUtil.getJMXJson());
return serializeToThrift(response, protocolFactory_);
}
/**
* Get Java version, input arguments and system properties.
*/
public static String getJavaVersion() {
RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();
StringBuilder sb = new StringBuilder();
sb.append("Java Input arguments:\n");
sb.append(Joiner.on(" ").join(runtime.getInputArguments()));
sb.append("\nJava System properties:\n");
for (Map.Entry<String, String> entry: runtime.getSystemProperties().entrySet()) {
sb.append(entry.getKey() + ":" + entry.getValue() + "\n");
}
return sb.toString();
}
}