blob: 0090c4ed0c9fe73518267c2966a54fe8f9563601 [file] [log] [blame]
/*=========================================================================
* Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
* This product is protected by U.S. and international copyright
* and intellectual property laws. Pivotal products are covered by
* one or more patents listed at http://www.pivotal.io/patents.
*=========================================================================
*/
package com.gemstone.gemfire.modules.util;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.gemstone.gemfire.cache.GemFireCache;
import com.gemstone.gemfire.cache.control.ResourceManager;
public class ResourceManagerValidator {
private static final Pattern DIGIT_PATTERN = Pattern.compile("(\\d+|[^\\d]+)");
public static void validateJavaStartupParameters(GemFireCache cache) {
// Get the input arguments
ResourceManager rm = cache.getResourceManager();
RuntimeMXBean runtimeBean = ManagementFactory.getRuntimeMXBean();
List<String> inputArguments = runtimeBean.getInputArguments();
if (cache.getLogger().fineEnabled()) {
cache.getLogger().fine("Full input java arguments: " + inputArguments);
}
// Validate the arguments based on VM vendor
String vmVendor = runtimeBean.getVmVendor();
if (vmVendor.startsWith("Sun") || vmVendor.startsWith("Apple")) {
// java.vm.vendor = Sun Microsystems Inc. || java.vm.vendor = Apple Inc.
validateSunArguments(cache, rm, inputArguments);
} else if (vmVendor.startsWith("IBM")) {
// java.vm.vendor = IBM Corporation
// TODO validate IBM input arguments
} else if (vmVendor.startsWith("BEA")) {
// java.vm.vendor = BEA Systems, Inc.
// TODO validate JRockit input arguments
}
}
private static void validateSunArguments(GemFireCache cache, ResourceManager rm, List<String> inputArguments) {
// Retrieve the -Xms, -Xmx, UseConcMarkSweepGC and CMSInitiatingOccupancyFraction arguments
String dashXms=null, dashXmx=null, useCMS=null, cmsIOF=null;
for (String argument : inputArguments) {
if (argument.startsWith("-Xms")) {
dashXms = argument;
} else if (argument.startsWith("-Xmx")) {
dashXmx = argument;
} else if (argument.equals("-XX:+UseConcMarkSweepGC")) {
useCMS = argument;
} else if (argument.startsWith("-XX:CMSInitiatingOccupancyFraction")) {
cmsIOF = argument;
}
}
if (cache.getLogger().fineEnabled()) {
StringBuilder builder = new StringBuilder();
builder
.append("Relevant input java arguments: ")
.append("dashXms=")
.append(dashXms)
.append("; dashXmx=")
.append(dashXmx)
.append("; useCMS=")
.append(useCMS)
.append("; cmsIOF=")
.append(cmsIOF);
cache.getLogger().fine(builder.toString());
}
// Validate the heap parameters
validateJavaHeapParameters(cache, dashXms, dashXmx);
// Verify CMS is specified
verifyCMSGC(cache, useCMS);
// Verify CMSInitiatingOccupancyFraction is specified
verifyCMSInitiatingOccupancyFraction(cache, rm, cmsIOF);
}
private static void validateJavaHeapParameters(GemFireCache cache, String dashXms, String dashXmx) {
if (dashXms == null) {
cache.getLogger().warning("Setting the initial size of the heap (configured using -Xms) is recommended so that GemFire cache eviction is optimal");
} else if (dashXmx == null) {
cache.getLogger().warning("Setting the maximum size of the heap (configured using -Xmx) is recommended so that GemFire cache eviction is optimal");
} else {
// Neither heap parameter is null. Parse them and verify they are the same.
List<String> dashXmsList = splitAtDigits(dashXms);
String dashXmsStr = dashXmsList.get(1);
List<String> dashXmxList = splitAtDigits(dashXmx);
String dashXmxStr = dashXmxList.get(1);
if (!dashXmsStr.equals(dashXmxStr)) {
StringBuilder builder = new StringBuilder();
builder
.append("Setting the initial (")
.append(dashXmsStr)
.append(dashXmsList.get(2))
.append(") and maximum (")
.append(dashXmxStr)
.append(dashXmxList.get(2))
.append(") sizes of the heap the same is recommended so that GemFire cache eviction is optimal");
cache.getLogger().warning(builder.toString());
}
}
}
private static void verifyCMSGC(GemFireCache cache, String useCMS) {
if (useCMS == null) {
cache.getLogger().warning("Using the concurrent garbage collector (configured using -XX:+UseConcMarkSweepGC) is recommended so that GemFire cache eviction is optimal");
}
}
private static void verifyCMSInitiatingOccupancyFraction(GemFireCache cache, ResourceManager rm, String cmsIOF) {
if (cmsIOF == null) {
cache.getLogger().warning("Setting the CMS initiating occupancy fraction (configured using -XX:CMSInitiatingOccupancyFraction=N) is recommended so that GemFire cache eviction is optimal");
} else {
// Parse the CMSInitiatingOccupancyFraction. Verify it is less than both eviction and critical thresholds.
int cmsIOFVal = Integer.parseInt(cmsIOF.split("=")[1]);
float currentEvictionHeapPercentage = rm.getEvictionHeapPercentage();
if (currentEvictionHeapPercentage !=0 && currentEvictionHeapPercentage < cmsIOFVal) {
cache.getLogger().warning("Setting the CMS initiating occupancy fraction (" + cmsIOFVal + ") less than the eviction heap percentage (" + currentEvictionHeapPercentage + ") is recommended so that GemFire cache eviction is optimal");
}
float currentCriticalHeapPercentage = rm.getCriticalHeapPercentage();
if (currentCriticalHeapPercentage !=0 && currentCriticalHeapPercentage < cmsIOFVal) {
cache.getLogger().warning("Setting the CMS initiating occupancy fraction (" + cmsIOFVal + ") less than the critical heap percentage (" + currentCriticalHeapPercentage + ") is recommended so that GemFire cache eviction is optimal");
}
}
}
private static List<String> splitAtDigits(String input) {
Matcher matcher = DIGIT_PATTERN.matcher(input);
List<String> result = new ArrayList<String>();
while (matcher.find()) {
result.add(matcher.group());
}
return result;
}
private ResourceManagerValidator() {}
}