浏览代码

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
Jason Tedor 9 年之前
父节点
当前提交
8004c51c17

+ 2 - 0
core/src/main/java/org/elasticsearch/bootstrap/Bootstrap.java

@@ -135,6 +135,8 @@ final class Bootstrap {
 
         JNANatives.trySetMaxNumberOfThreads();
 
+        JNANatives.trySetMaxSizeVirtualMemory();
+
         // init lucene random seed. it will use /dev/urandom where available:
         StringHelper.randomId();
     }

+ 24 - 0
core/src/main/java/org/elasticsearch/bootstrap/BootstrapCheck.java

@@ -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;
+        }
+
+    }
+
 }

+ 1 - 0
core/src/main/java/org/elasticsearch/bootstrap/JNACLibrary.java

@@ -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 {

+ 13 - 0
core/src/main/java/org/elasticsearch/bootstrap/JNANatives.java

@@ -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) {

+ 27 - 0
core/src/test/java/org/elasticsearch/bootstrap/BootstrapCheckTests.java

@@ -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()])));

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

@@ -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));
+        }
+    }
+
 }