/*
* 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.geode.internal.statistics;
import org.apache.geode.*;
import org.apache.geode.internal.PureJavaMode;
import org.apache.geode.internal.net.SocketCreator;
import org.apache.geode.internal.i18n.LocalizedStrings;
import org.apache.geode.internal.statistics.platform.LinuxProcFsStatistics;
import org.apache.geode.internal.statistics.platform.LinuxProcessStats;
import org.apache.geode.internal.statistics.platform.LinuxSystemStats;
import org.apache.geode.internal.statistics.platform.OSXProcessStats;
import org.apache.geode.internal.statistics.platform.OSXSystemStats;
import org.apache.geode.internal.statistics.platform.OsStatisticsFactory;
import org.apache.geode.internal.statistics.platform.ProcessStats;
import org.apache.geode.internal.statistics.platform.SolarisProcessStats;
import org.apache.geode.internal.statistics.platform.SolarisSystemStats;
import org.apache.geode.internal.statistics.platform.WindowsProcessStats;
import org.apache.geode.internal.statistics.platform.WindowsSystemStats;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* Provides native methods which fetch operating system statistics.
*/
public class HostStatHelper {
static final int SOLARIS_CODE = 1; // Sparc Solaris
static final int WINDOWS_CODE = 2;
static final int LINUX_CODE = 3; // x86 Linux
static final int OSX_CODE = 4; // Mac OS X
static final int PROCESS_STAT_FLAG = 1;
static final int SYSTEM_STAT_FLAG = 2;
static final int osCode;
static {
String osName = System.getProperty("os.name", "unknown");
if (!PureJavaMode.osStatsAreAvailable()) {
throw new RuntimeException(
LocalizedStrings.HostStatHelper_HOSTSTATHELPER_NOT_ALLOWED_IN_PURE_JAVA_MODE
.toLocalizedString());
} else if (osName.equals("SunOS")) {
osCode = SOLARIS_CODE;
} else if (osName.startsWith("Windows")) {
osCode = WINDOWS_CODE;
} else if (osName.startsWith("Linux")) {
osCode = LINUX_CODE;
} else if (osName.equals("Mac OS X")) {
osCode = OSX_CODE;
} else {
throw new InternalGemFireException(
LocalizedStrings.HostStatHelper_UNSUPPORTED_OS_0_SUPPORTED_OSS_ARE_SUNOSSPARC_SOLARIS_LINUXX86_AND_WINDOWS
.toLocalizedString(osName));
}
}
public static boolean isWindows() {
return osCode == WINDOWS_CODE;
}
public static boolean isUnix() {
return osCode != WINDOWS_CODE;
}
public static boolean isSolaris() {
return osCode == SOLARIS_CODE;
}
public static boolean isLinux() {
return osCode == LINUX_CODE;
}
public static boolean isOSX() {
return osCode == OSX_CODE;
}
private HostStatHelper() {
// instances are not allowed
}
static int initOSStats() {
if (isLinux()) {
return LinuxProcFsStatistics.init();
} else {
return HostStatHelper.init();
}
}
static void closeOSStats() {
if (isLinux()) {
LinuxProcFsStatistics.close();
} else {
HostStatHelper.close();
}
}
static void readyRefreshOSStats() {
if (isLinux()) {
LinuxProcFsStatistics.readyRefresh();
} else {
HostStatHelper.readyRefresh();
}
}
/**
* Allocates and initializes any resources required to sample operating system statistics. returns
* 0 if initialization succeeded
*/
private static native int init();
/**
* Frees up resources used by this class. Once close is called this class can no longer be used.
*/
private static native void close();
/**
* Should be called before any calls to the refresh methods. On some platforms if this is not
* called then the refesh methods will just keep returning the same old data.
*/
private static native void readyRefresh();
/**
* Refreshes the specified process stats instance by fetching the current OS values for the given
* stats and storing them in the instance.
*/
private static void refreshProcess(LocalStatisticsImpl s) {
int pid = (int) s.getNumericId();
if (isLinux()) {
LinuxProcFsStatistics.refreshProcess(pid, s._getIntStorage(), s._getLongStorage(),
s._getDoubleStorage());
} else {
refreshProcess(pid, s._getIntStorage(), s._getLongStorage(), s._getDoubleStorage());
}
}
private static native void refreshProcess(int pid, int[] ints, long[] longs, double[] doubles);
/**
* Refreshes the specified system stats instance by fetching the current OS values for the local
* machine and storing them in the instance.
*/
private static void refreshSystem(LocalStatisticsImpl s) {
if (isLinux()) {
LinuxProcFsStatistics.refreshSystem(s._getIntStorage(), s._getLongStorage(),
s._getDoubleStorage());
} else {
refreshSystem(s._getIntStorage(), s._getLongStorage(), s._getDoubleStorage());
}
}
private static native void refreshSystem(int[] ints, long[] longs, double[] doubles);
/**
* The call should have already checked to make sure usesSystemCalls returns true.
*/
public static void refresh(LocalStatisticsImpl stats) {
int flags = stats.getOsStatFlags();
if ((flags & PROCESS_STAT_FLAG) != 0) {
HostStatHelper.refreshProcess(stats);
} else if ((flags & SYSTEM_STAT_FLAG) != 0) {
HostStatHelper.refreshSystem(stats);
} else {
throw new RuntimeException(LocalizedStrings.HostStatHelper_UNEXPECTED_OS_STATS_FLAGS_0
.toLocalizedString(Integer.valueOf(flags)));
}
}
/**
* Creates and returns a {@link Statistics} with the given pid and name. The resource's stats will
* contain a snapshot of the current statistic values for the specified process.
*/
public static Statistics newProcess(OsStatisticsFactory f, long pid, String name) {
Statistics stats;
switch (osCode) {
case SOLARIS_CODE:
stats = f.createOsStatistics(SolarisProcessStats.getType(), name, pid, PROCESS_STAT_FLAG);
break;
case LINUX_CODE:
stats = f.createOsStatistics(LinuxProcessStats.getType(), name, pid, PROCESS_STAT_FLAG);
break;
case OSX_CODE:
stats = f.createOsStatistics(OSXProcessStats.getType(), name, pid, PROCESS_STAT_FLAG);
break;
case WINDOWS_CODE:
stats = f.createOsStatistics(WindowsProcessStats.getType(), name, pid, PROCESS_STAT_FLAG);
break;
default:
throw new InternalGemFireException(
LocalizedStrings.HostStatHelper_UNHANDLED_OSCODE_0_HOSTSTATHELPERNEWPROCESS
.toLocalizedString(Integer.valueOf(osCode)));
}
// Note we don't call refreshProcess since we only want the manager to do that
return stats;
}
/**
* Creates a new <code>ProcessStats</code> instance that wraps the given <code>Statistics</code>.
*
* @see #newProcess
* @since GemFire 3.5
*/
static ProcessStats newProcessStats(Statistics stats) {
switch (osCode) {
case SOLARIS_CODE:
return SolarisProcessStats.createProcessStats(stats);
case LINUX_CODE:
return LinuxProcessStats.createProcessStats(stats);
case WINDOWS_CODE:
return WindowsProcessStats.createProcessStats(stats);
case OSX_CODE:
return OSXProcessStats.createProcessStats(stats);
default:
throw new InternalGemFireException(
LocalizedStrings.HostStatHelper_UNHANDLED_OSCODE_0_HOSTSTATHELPERNEWPROCESSSTATS
.toLocalizedString(Integer.valueOf(osCode)));
}
}
/**
* Creates and returns a {@link Statistics} with the current machine's stats. The resource's stats
* will contain a snapshot of the current statistic values for the local machine.
*/
static void newSystem(OsStatisticsFactory f) {
Statistics stats;
switch (osCode) {
case SOLARIS_CODE:
stats = f.createOsStatistics(SolarisSystemStats.getType(), getHostSystemName(),
getHostSystemId(), SYSTEM_STAT_FLAG);
break;
case LINUX_CODE:
stats = f.createOsStatistics(LinuxSystemStats.getType(), getHostSystemName(),
getHostSystemId(), SYSTEM_STAT_FLAG);
break;
case WINDOWS_CODE:
stats = f.createOsStatistics(WindowsSystemStats.getType(), getHostSystemName(),
getHostSystemId(), SYSTEM_STAT_FLAG);
break;
case OSX_CODE:
stats = f.createOsStatistics(OSXSystemStats.getType(), getHostSystemName(),
getHostSystemId(), SYSTEM_STAT_FLAG);
break;
default:
throw new InternalGemFireException(
LocalizedStrings.HostStatHelper_UNHANDLED_OSCODE_0_HOSTSTATHELPERNEWSYSTEM
.toLocalizedString(Integer.valueOf(osCode)));
}
if (stats instanceof LocalStatisticsImpl) {
refreshSystem((LocalStatisticsImpl) stats);
} // otherwise its a Dummy implementation so do nothing
}
/**
* @return this machine's fully qualified hostname or "unknownHostName" if one cannot be found.
*/
private static String getHostSystemName() {
String hostname = "unknownHostName";
try {
InetAddress addr = SocketCreator.getLocalHost();
hostname = addr.getCanonicalHostName();
} catch (UnknownHostException uhe) {
}
return hostname;
}
/**
* Generate a systemid based off of the ip address of the host. This duplicates the common
* implementation of <code>long gethostid(void) </code>. Punt on the ipv6 case and just use the
* same algorithm.
*
* @return a psuedo unique id based on the ip address
*/
private static long getHostSystemId() {
long id = 0L;
try {
InetAddress host = SocketCreator.getLocalHost();
byte[] addr = host.getAddress();
id = (addr[1] & 0xFFL) << 24 | (addr[0] & 0xFFL) << 16 | (addr[3] & 0xFFL) << 8
| (addr[2] & 0xFFL) << 0;
} catch (UnknownHostException uhe) {
}
return id;
}
}