Skip to content

Commit 8004c51

Browse files
committed
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
1 parent c52b1f3 commit 8004c51

File tree

6 files changed

+91
-0
lines changed

6 files changed

+91
-0
lines changed

core/src/main/java/org/elasticsearch/bootstrap/Bootstrap.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,8 @@ public boolean handle(int code) {
135135

136136
JNANatives.trySetMaxNumberOfThreads();
137137

138+
JNANatives.trySetMaxSizeVirtualMemory();
139+
138140
// init lucene random seed. it will use /dev/urandom where available:
139141
StringHelper.randomId();
140142
}

core/src/main/java/org/elasticsearch/bootstrap/BootstrapCheck.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ private static List<Check> checks(final Settings settings) {
123123
if (Constants.LINUX) {
124124
checks.add(new MaxNumberOfThreadsCheck());
125125
}
126+
checks.add(new MaxSizeVirtualMemoryCheck());
126127
return Collections.unmodifiableList(checks);
127128
}
128129

@@ -249,4 +250,27 @@ long getMaxNumberOfThreads() {
249250

250251
}
251252

253+
static class MaxSizeVirtualMemoryCheck implements Check {
254+
255+
@Override
256+
public boolean check() {
257+
return getMaxSizeVirtualMemory() != Long.MIN_VALUE && getMaxSizeVirtualMemory() != JNACLibrary.RLIM_INFINITY;
258+
}
259+
260+
@Override
261+
public String errorMessage() {
262+
return String.format(
263+
Locale.ROOT,
264+
"max size virtual memory [%d] for user [%s] likely too low, increase to [unlimited]",
265+
getMaxSizeVirtualMemory(),
266+
BootstrapInfo.getSystemProperties().get("user.name"));
267+
}
268+
269+
// visible for testing
270+
long getMaxSizeVirtualMemory() {
271+
return JNANatives.MAX_SIZE_VIRTUAL_MEMORY;
272+
}
273+
274+
}
275+
252276
}

core/src/main/java/org/elasticsearch/bootstrap/JNACLibrary.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ final class JNACLibrary {
3939
public static final int MCL_CURRENT = 1;
4040
public static final int ENOMEM = 12;
4141
public static final int RLIMIT_MEMLOCK = Constants.MAC_OS_X ? 6 : 8;
42+
public static final int RLIMIT_AS = Constants.MAC_OS_X ? 5 : 9;
4243
public static final long RLIM_INFINITY = Constants.MAC_OS_X ? 9223372036854775807L : -1L;
4344

4445
static {

core/src/main/java/org/elasticsearch/bootstrap/JNANatives.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ private JNANatives() {}
5252
// the user ID that owns the running Elasticsearch process
5353
static long MAX_NUMBER_OF_THREADS = -1;
5454

55+
static long MAX_SIZE_VIRTUAL_MEMORY = Long.MIN_VALUE;
56+
5557
static void tryMlockall() {
5658
int errno = Integer.MIN_VALUE;
5759
String errMsg = null;
@@ -124,6 +126,17 @@ static void trySetMaxNumberOfThreads() {
124126
}
125127
}
126128

129+
static void trySetMaxSizeVirtualMemory() {
130+
if (Constants.LINUX || Constants.MAC_OS_X) {
131+
final JNACLibrary.Rlimit rlimit = new JNACLibrary.Rlimit();
132+
if (JNACLibrary.getrlimit(JNACLibrary.RLIMIT_AS, rlimit) == 0) {
133+
MAX_SIZE_VIRTUAL_MEMORY = rlimit.rlim_cur.longValue();
134+
} else {
135+
logger.warn("unable to retrieve max size virtual memory [" + JNACLibrary.strerror(Native.getLastError()) + "]");
136+
}
137+
}
138+
}
139+
127140
static String rlimitToString(long value) {
128141
assert Constants.LINUX || Constants.MAC_OS_X;
129142
if (value == JNACLibrary.RLIM_INFINITY) {

core/src/test/java/org/elasticsearch/bootstrap/BootstrapCheckTests.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,33 @@ long getMaxNumberOfThreads() {
157157
BootstrapCheck.check(true, Collections.singletonList(check));
158158
}
159159

160+
public void testMaxSizeVirtualMemory() {
161+
final long limit = JNACLibrary.RLIM_INFINITY;
162+
final AtomicLong maxSizeVirtualMemory = new AtomicLong(randomInt());
163+
final BootstrapCheck.MaxSizeVirtualMemoryCheck check = new BootstrapCheck.MaxSizeVirtualMemoryCheck() {
164+
@Override
165+
long getMaxSizeVirtualMemory() {
166+
return maxSizeVirtualMemory.get();
167+
}
168+
};
169+
170+
try {
171+
BootstrapCheck.check(true, Collections.singletonList(check));
172+
fail("should have failed due to max size virtual memory too low");
173+
} catch (final RuntimeException e) {
174+
assertThat(e.getMessage(), containsString("max size virtual memory"));
175+
}
176+
177+
maxSizeVirtualMemory.set(limit);
178+
179+
BootstrapCheck.check(true, Collections.singletonList(check));
180+
181+
// nothing should happen if max size virtual memory is not
182+
// available
183+
maxSizeVirtualMemory.set(Long.MIN_VALUE);
184+
BootstrapCheck.check(true, Collections.singletonList(check));
185+
}
186+
160187
public void testEnforceLimits() {
161188
final Set<Setting> enforceSettings = BootstrapCheck.enforceSettings();
162189
final Setting setting = randomFrom(Arrays.asList(enforceSettings.toArray(new Setting[enforceSettings.size()])));

qa/evil-tests/src/test/java/org/elasticsearch/bootstrap/EvilJNANativesTests.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@
2727
import java.nio.file.Files;
2828
import java.util.List;
2929

30+
import static org.hamcrest.Matchers.anyOf;
3031
import static org.hamcrest.Matchers.equalTo;
32+
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
3133

3234
public class EvilJNANativesTests extends ESTestCase {
3335

@@ -49,4 +51,26 @@ public void testSetMaximumNumberOfThreads() throws IOException {
4951
assertThat(JNANatives.MAX_NUMBER_OF_THREADS, equalTo(-1L));
5052
}
5153
}
54+
55+
public void testSetMaxSizeVirtualMemory() throws IOException {
56+
if (Constants.LINUX) {
57+
final List<String> lines = Files.readAllLines(PathUtils.get("/proc/self/limits"));
58+
if (!lines.isEmpty()) {
59+
for (String line : lines) {
60+
if (line != null && line.startsWith("Max address space")) {
61+
final String[] fields = line.split("\\s+");
62+
final String limit = fields[3];
63+
assertEquals(JNANatives.rlimitToString(JNANatives.MAX_SIZE_VIRTUAL_MEMORY), limit);
64+
return;
65+
}
66+
}
67+
}
68+
fail("should have read max size virtual memory from /proc/self/limits");
69+
} else if (Constants.MAC_OS_X) {
70+
assertThat(JNANatives.MAX_SIZE_VIRTUAL_MEMORY, anyOf(equalTo(Long.MIN_VALUE), greaterThanOrEqualTo(0L)));
71+
} else {
72+
assertThat(JNANatives.MAX_SIZE_VIRTUAL_MEMORY, equalTo(Long.MIN_VALUE));
73+
}
74+
}
75+
5276
}

0 commit comments

Comments
 (0)