Add heap size bootstrap check
This commit adds a bootstrap check to ensure that the initial heap size and max heap size are set equal to each other.
This commit is contained in:
parent
5ca4304b23
commit
4f5d73bcb7
|
@ -26,6 +26,7 @@ import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.common.transport.BoundTransportAddress;
|
import org.elasticsearch.common.transport.BoundTransportAddress;
|
||||||
import org.elasticsearch.common.transport.TransportAddress;
|
import org.elasticsearch.common.transport.TransportAddress;
|
||||||
import org.elasticsearch.discovery.zen.elect.ElectMasterService;
|
import org.elasticsearch.discovery.zen.elect.ElectMasterService;
|
||||||
|
import org.elasticsearch.monitor.jvm.JvmInfo;
|
||||||
import org.elasticsearch.monitor.process.ProcessProbe;
|
import org.elasticsearch.monitor.process.ProcessProbe;
|
||||||
import org.elasticsearch.node.Node;
|
import org.elasticsearch.node.Node;
|
||||||
|
|
||||||
|
@ -108,6 +109,7 @@ final class BootstrapCheck {
|
||||||
// the list of checks to execute
|
// the list of checks to execute
|
||||||
static List<Check> checks(final Settings settings) {
|
static List<Check> checks(final Settings settings) {
|
||||||
final List<Check> checks = new ArrayList<>();
|
final List<Check> checks = new ArrayList<>();
|
||||||
|
checks.add(new HeapSizeCheck());
|
||||||
final FileDescriptorCheck fileDescriptorCheck
|
final FileDescriptorCheck fileDescriptorCheck
|
||||||
= Constants.MAC_OS_X ? new OsXFileDescriptorCheck() : new FileDescriptorCheck();
|
= Constants.MAC_OS_X ? new OsXFileDescriptorCheck() : new FileDescriptorCheck();
|
||||||
checks.add(fileDescriptorCheck);
|
checks.add(fileDescriptorCheck);
|
||||||
|
@ -143,6 +145,38 @@ final class BootstrapCheck {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class HeapSizeCheck implements BootstrapCheck.Check {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean check() {
|
||||||
|
final long initialHeapSize = getInitialHeapSize();
|
||||||
|
final long maxHeapSize = getMaxHeapSize();
|
||||||
|
return initialHeapSize != 0 && maxHeapSize != 0 && initialHeapSize != maxHeapSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String errorMessage() {
|
||||||
|
return String.format(
|
||||||
|
Locale.ROOT,
|
||||||
|
"initial heap size [%d] not equal to maximum heap size [%d]; " +
|
||||||
|
"this can cause resize pauses and prevents mlockall from locking the entire heap",
|
||||||
|
getInitialHeapSize(),
|
||||||
|
getMaxHeapSize()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// visible for testing
|
||||||
|
long getInitialHeapSize() {
|
||||||
|
return JvmInfo.jvmInfo().getConfiguredInitialHeapSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
// visible for testing
|
||||||
|
long getMaxHeapSize() {
|
||||||
|
return JvmInfo.jvmInfo().getConfiguredMaxHeapSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
static class OsXFileDescriptorCheck extends FileDescriptorCheck {
|
static class OsXFileDescriptorCheck extends FileDescriptorCheck {
|
||||||
|
|
||||||
public OsXFileDescriptorCheck() {
|
public OsXFileDescriptorCheck() {
|
||||||
|
|
|
@ -114,15 +114,33 @@ public class JvmInfo implements Streamable, ToXContent {
|
||||||
Class<?> vmOptionClazz = Class.forName("com.sun.management.VMOption");
|
Class<?> vmOptionClazz = Class.forName("com.sun.management.VMOption");
|
||||||
PlatformManagedObject hotSpotDiagnosticMXBean = ManagementFactory.getPlatformMXBean(clazz);
|
PlatformManagedObject hotSpotDiagnosticMXBean = ManagementFactory.getPlatformMXBean(clazz);
|
||||||
Method vmOptionMethod = clazz.getMethod("getVMOption", String.class);
|
Method vmOptionMethod = clazz.getMethod("getVMOption", String.class);
|
||||||
Object useCompressedOopsVmOption = vmOptionMethod.invoke(hotSpotDiagnosticMXBean, "UseCompressedOops");
|
|
||||||
Method valueMethod = vmOptionClazz.getMethod("getValue");
|
Method valueMethod = vmOptionClazz.getMethod("getValue");
|
||||||
|
|
||||||
|
try {
|
||||||
|
Object useCompressedOopsVmOption = vmOptionMethod.invoke(hotSpotDiagnosticMXBean, "UseCompressedOops");
|
||||||
info.useCompressedOops = (String) valueMethod.invoke(useCompressedOopsVmOption);
|
info.useCompressedOops = (String) valueMethod.invoke(useCompressedOopsVmOption);
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
Object useG1GCVmOption = vmOptionMethod.invoke(hotSpotDiagnosticMXBean, "UseG1GC");
|
Object useG1GCVmOption = vmOptionMethod.invoke(hotSpotDiagnosticMXBean, "UseG1GC");
|
||||||
info.useG1GC = (String) valueMethod.invoke(useG1GCVmOption);
|
info.useG1GC = (String) valueMethod.invoke(useG1GCVmOption);
|
||||||
} catch (Throwable t) {
|
} catch (Exception ignored) {
|
||||||
// unable to deduce the state of compressed oops
|
}
|
||||||
info.useCompressedOops = "unknown";
|
|
||||||
info.useG1GC = "unknown";
|
try {
|
||||||
|
Object initialHeapSizeVmOption = vmOptionMethod.invoke(hotSpotDiagnosticMXBean, "InitialHeapSize");
|
||||||
|
info.configuredInitialHeapSize = Long.parseLong((String) valueMethod.invoke(initialHeapSizeVmOption));
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Object maxHeapSizeVmOption = vmOptionMethod.invoke(hotSpotDiagnosticMXBean, "MaxHeapSize");
|
||||||
|
info.configuredMaxHeapSize = Long.parseLong((String) valueMethod.invoke(maxHeapSizeVmOption));
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
INSTANCE = info;
|
INSTANCE = info;
|
||||||
|
@ -146,6 +164,9 @@ public class JvmInfo implements Streamable, ToXContent {
|
||||||
|
|
||||||
long startTime = -1;
|
long startTime = -1;
|
||||||
|
|
||||||
|
private long configuredInitialHeapSize;
|
||||||
|
private long configuredMaxHeapSize;
|
||||||
|
|
||||||
Mem mem;
|
Mem mem;
|
||||||
|
|
||||||
String[] inputArguments;
|
String[] inputArguments;
|
||||||
|
@ -159,9 +180,9 @@ public class JvmInfo implements Streamable, ToXContent {
|
||||||
String[] gcCollectors = Strings.EMPTY_ARRAY;
|
String[] gcCollectors = Strings.EMPTY_ARRAY;
|
||||||
String[] memoryPools = Strings.EMPTY_ARRAY;
|
String[] memoryPools = Strings.EMPTY_ARRAY;
|
||||||
|
|
||||||
private String useCompressedOops;
|
private String useCompressedOops = "unknown";
|
||||||
|
|
||||||
private String useG1GC;
|
private String useG1GC = "unknown";
|
||||||
|
|
||||||
private JvmInfo() {
|
private JvmInfo() {
|
||||||
}
|
}
|
||||||
|
@ -286,6 +307,14 @@ public class JvmInfo implements Streamable, ToXContent {
|
||||||
return this.systemProperties;
|
return this.systemProperties;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long getConfiguredInitialHeapSize() {
|
||||||
|
return configuredInitialHeapSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getConfiguredMaxHeapSize() {
|
||||||
|
return configuredMaxHeapSize;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The value of the JVM flag UseCompressedOops, if available otherwise
|
* The value of the JVM flag UseCompressedOops, if available otherwise
|
||||||
* "unknown". The value "unknown" indicates that an attempt was
|
* "unknown". The value "unknown" indicates that an attempt was
|
||||||
|
|
|
@ -137,6 +137,49 @@ public class BootstrapCheckTests extends ESTestCase {
|
||||||
assertThat(suppressed[1], hasToString(containsString("second")));
|
assertThat(suppressed[1], hasToString(containsString("second")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testHeapSizeCheck() {
|
||||||
|
final int initial = randomIntBetween(0, Integer.MAX_VALUE - 1);
|
||||||
|
final int max = randomIntBetween(initial + 1, Integer.MAX_VALUE);
|
||||||
|
final AtomicLong initialHeapSize = new AtomicLong(initial);
|
||||||
|
final AtomicLong maxHeapSize = new AtomicLong(max);
|
||||||
|
|
||||||
|
final BootstrapCheck.HeapSizeCheck check = new BootstrapCheck.HeapSizeCheck() {
|
||||||
|
@Override
|
||||||
|
long getInitialHeapSize() {
|
||||||
|
return initialHeapSize.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
long getMaxHeapSize() {
|
||||||
|
return maxHeapSize.get();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
BootstrapCheck.check(true, Collections.singletonList(check), "testHeapSizeCheck");
|
||||||
|
fail("should have failed to initial heap size not equal to max heap size");
|
||||||
|
} catch (final RuntimeException e) {
|
||||||
|
assertThat(
|
||||||
|
e.getMessage(),
|
||||||
|
containsString("initial heap size [" + initialHeapSize.get() + "] " +
|
||||||
|
"not equal to maximum heap size [" + maxHeapSize.get() + "]")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
initialHeapSize.set(maxHeapSize.get());
|
||||||
|
|
||||||
|
BootstrapCheck.check(true, Collections.singletonList(check), "testHeapSizeCheck");
|
||||||
|
|
||||||
|
// nothing should happen if the initial heap size or the max
|
||||||
|
// heap size is not available
|
||||||
|
if (randomBoolean()) {
|
||||||
|
initialHeapSize.set(0);
|
||||||
|
} else {
|
||||||
|
maxHeapSize.set(0);
|
||||||
|
}
|
||||||
|
BootstrapCheck.check(true, Collections.singletonList(check), "testHeapSizeCheck");
|
||||||
|
}
|
||||||
|
|
||||||
public void testFileDescriptorLimits() {
|
public void testFileDescriptorLimits() {
|
||||||
final boolean osX = randomBoolean(); // simulates OS X versus non-OS X
|
final boolean osX = randomBoolean(); // simulates OS X versus non-OS X
|
||||||
final int limit = osX ? 10240 : 1 << 16;
|
final int limit = osX ? 10240 : 1 << 16;
|
||||||
|
|
Loading…
Reference in New Issue