/* * 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; } }