Add max size virtual memory check
This commit adds a bootstrap check on Linux and OS X for the max size of virtual memory (address space) to the user running the Elasticsearch process. Closes #16935
This commit is contained in:
parent
c52b1f3a7c
commit
8004c51c17
|
@ -135,6 +135,8 @@ final class Bootstrap {
|
|||
|
||||
JNANatives.trySetMaxNumberOfThreads();
|
||||
|
||||
JNANatives.trySetMaxSizeVirtualMemory();
|
||||
|
||||
// init lucene random seed. it will use /dev/urandom where available:
|
||||
StringHelper.randomId();
|
||||
}
|
||||
|
|
|
@ -123,6 +123,7 @@ final class BootstrapCheck {
|
|||
if (Constants.LINUX) {
|
||||
checks.add(new MaxNumberOfThreadsCheck());
|
||||
}
|
||||
checks.add(new MaxSizeVirtualMemoryCheck());
|
||||
return Collections.unmodifiableList(checks);
|
||||
}
|
||||
|
||||
|
@ -249,4 +250,27 @@ final class BootstrapCheck {
|
|||
|
||||
}
|
||||
|
||||
static class MaxSizeVirtualMemoryCheck implements Check {
|
||||
|
||||
@Override
|
||||
public boolean check() {
|
||||
return getMaxSizeVirtualMemory() != Long.MIN_VALUE && getMaxSizeVirtualMemory() != JNACLibrary.RLIM_INFINITY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String errorMessage() {
|
||||
return String.format(
|
||||
Locale.ROOT,
|
||||
"max size virtual memory [%d] for user [%s] likely too low, increase to [unlimited]",
|
||||
getMaxSizeVirtualMemory(),
|
||||
BootstrapInfo.getSystemProperties().get("user.name"));
|
||||
}
|
||||
|
||||
// visible for testing
|
||||
long getMaxSizeVirtualMemory() {
|
||||
return JNANatives.MAX_SIZE_VIRTUAL_MEMORY;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ final class JNACLibrary {
|
|||
public static final int MCL_CURRENT = 1;
|
||||
public static final int ENOMEM = 12;
|
||||
public static final int RLIMIT_MEMLOCK = Constants.MAC_OS_X ? 6 : 8;
|
||||
public static final int RLIMIT_AS = Constants.MAC_OS_X ? 5 : 9;
|
||||
public static final long RLIM_INFINITY = Constants.MAC_OS_X ? 9223372036854775807L : -1L;
|
||||
|
||||
static {
|
||||
|
|
|
@ -52,6 +52,8 @@ class JNANatives {
|
|||
// the user ID that owns the running Elasticsearch process
|
||||
static long MAX_NUMBER_OF_THREADS = -1;
|
||||
|
||||
static long MAX_SIZE_VIRTUAL_MEMORY = Long.MIN_VALUE;
|
||||
|
||||
static void tryMlockall() {
|
||||
int errno = Integer.MIN_VALUE;
|
||||
String errMsg = null;
|
||||
|
@ -124,6 +126,17 @@ class JNANatives {
|
|||
}
|
||||
}
|
||||
|
||||
static void trySetMaxSizeVirtualMemory() {
|
||||
if (Constants.LINUX || Constants.MAC_OS_X) {
|
||||
final JNACLibrary.Rlimit rlimit = new JNACLibrary.Rlimit();
|
||||
if (JNACLibrary.getrlimit(JNACLibrary.RLIMIT_AS, rlimit) == 0) {
|
||||
MAX_SIZE_VIRTUAL_MEMORY = rlimit.rlim_cur.longValue();
|
||||
} else {
|
||||
logger.warn("unable to retrieve max size virtual memory [" + JNACLibrary.strerror(Native.getLastError()) + "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static String rlimitToString(long value) {
|
||||
assert Constants.LINUX || Constants.MAC_OS_X;
|
||||
if (value == JNACLibrary.RLIM_INFINITY) {
|
||||
|
|
|
@ -157,6 +157,33 @@ public class BootstrapCheckTests extends ESTestCase {
|
|||
BootstrapCheck.check(true, Collections.singletonList(check));
|
||||
}
|
||||
|
||||
public void testMaxSizeVirtualMemory() {
|
||||
final long limit = JNACLibrary.RLIM_INFINITY;
|
||||
final AtomicLong maxSizeVirtualMemory = new AtomicLong(randomInt());
|
||||
final BootstrapCheck.MaxSizeVirtualMemoryCheck check = new BootstrapCheck.MaxSizeVirtualMemoryCheck() {
|
||||
@Override
|
||||
long getMaxSizeVirtualMemory() {
|
||||
return maxSizeVirtualMemory.get();
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
BootstrapCheck.check(true, Collections.singletonList(check));
|
||||
fail("should have failed due to max size virtual memory too low");
|
||||
} catch (final RuntimeException e) {
|
||||
assertThat(e.getMessage(), containsString("max size virtual memory"));
|
||||
}
|
||||
|
||||
maxSizeVirtualMemory.set(limit);
|
||||
|
||||
BootstrapCheck.check(true, Collections.singletonList(check));
|
||||
|
||||
// nothing should happen if max size virtual memory is not
|
||||
// available
|
||||
maxSizeVirtualMemory.set(Long.MIN_VALUE);
|
||||
BootstrapCheck.check(true, Collections.singletonList(check));
|
||||
}
|
||||
|
||||
public void testEnforceLimits() {
|
||||
final Set<Setting> enforceSettings = BootstrapCheck.enforceSettings();
|
||||
final Setting setting = randomFrom(Arrays.asList(enforceSettings.toArray(new Setting[enforceSettings.size()])));
|
||||
|
|
|
@ -27,7 +27,9 @@ import java.io.IOException;
|
|||
import java.nio.file.Files;
|
||||
import java.util.List;
|
||||
|
||||
import static org.hamcrest.Matchers.anyOf;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
|
||||
|
||||
public class EvilJNANativesTests extends ESTestCase {
|
||||
|
||||
|
@ -49,4 +51,26 @@ public class EvilJNANativesTests extends ESTestCase {
|
|||
assertThat(JNANatives.MAX_NUMBER_OF_THREADS, equalTo(-1L));
|
||||
}
|
||||
}
|
||||
|
||||
public void testSetMaxSizeVirtualMemory() throws IOException {
|
||||
if (Constants.LINUX) {
|
||||
final List<String> lines = Files.readAllLines(PathUtils.get("/proc/self/limits"));
|
||||
if (!lines.isEmpty()) {
|
||||
for (String line : lines) {
|
||||
if (line != null && line.startsWith("Max address space")) {
|
||||
final String[] fields = line.split("\\s+");
|
||||
final String limit = fields[3];
|
||||
assertEquals(JNANatives.rlimitToString(JNANatives.MAX_SIZE_VIRTUAL_MEMORY), limit);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
fail("should have read max size virtual memory from /proc/self/limits");
|
||||
} else if (Constants.MAC_OS_X) {
|
||||
assertThat(JNANatives.MAX_SIZE_VIRTUAL_MEMORY, anyOf(equalTo(Long.MIN_VALUE), greaterThanOrEqualTo(0L)));
|
||||
} else {
|
||||
assertThat(JNANatives.MAX_SIZE_VIRTUAL_MEMORY, equalTo(Long.MIN_VALUE));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue