diff --git a/src/main/java/org/elasticsearch/bootstrap/JNACLibrary.java b/src/main/java/org/elasticsearch/bootstrap/JNACLibrary.java index 97bf98e60f6..b4344bd09ef 100644 --- a/src/main/java/org/elasticsearch/bootstrap/JNACLibrary.java +++ b/src/main/java/org/elasticsearch/bootstrap/JNACLibrary.java @@ -20,34 +20,58 @@ package org.elasticsearch.bootstrap; import com.sun.jna.Native; +import com.sun.jna.Structure; + +import org.apache.lucene.util.Constants; import org.elasticsearch.common.logging.ESLogger; import org.elasticsearch.common.logging.Loggers; +import java.util.Arrays; +import java.util.List; + /** * */ -class JNACLibrary { +final class JNACLibrary { private static final ESLogger logger = Loggers.getLogger(JNACLibrary.class); public static final int MCL_CURRENT = 1; - public static final int MCL_FUTURE = 2; - public static final int ENOMEM = 12; + public static final int RLIMIT_MEMLOCK = Constants.MAC_OS_X ? 6 : 8; static { try { Native.register("c"); } catch (UnsatisfiedLinkError e) { - logger.warn("unable to link C library. native methods (mlockall) will be disabled."); + logger.warn("unable to link C library. native methods (mlockall) will be disabled.", e); } } static native int mlockall(int flags); static native int geteuid(); + + /** corresponds to struct rlimit */ + public static final class Rlimit extends Structure implements Structure.ByReference { + public long rlim_cur = 0; + public long rlim_max = 0; + + @Override + protected List getFieldOrder() { + return Arrays.asList(new String[] { "rlim_cur", "rlim_max" }); + } + } + + static native int getrlimit(int resource, Rlimit rlimit); + + static native String strerror(int errno); private JNACLibrary() { } + + public static void main(String args[]) throws Exception { + JNANatives.tryMlockall(); + } } diff --git a/src/main/java/org/elasticsearch/bootstrap/JNANatives.java b/src/main/java/org/elasticsearch/bootstrap/JNANatives.java index eb29df85cdb..a9adce4641e 100644 --- a/src/main/java/org/elasticsearch/bootstrap/JNANatives.java +++ b/src/main/java/org/elasticsearch/bootstrap/JNANatives.java @@ -43,26 +43,40 @@ class JNANatives { static void tryMlockall() { int errno = Integer.MIN_VALUE; + String errMsg = null; + boolean rlimitSuccess = false; + long softLimit = 0; + long hardLimit = 0; + try { int result = JNACLibrary.mlockall(JNACLibrary.MCL_CURRENT); - if (result != 0) { - errno = Native.getLastError(); - } else { + if (result == 0) { LOCAL_MLOCKALL = true; + return; + } + + errno = Native.getLastError(); + errMsg = JNACLibrary.strerror(errno); + JNACLibrary.Rlimit rlimit = new JNACLibrary.Rlimit(); + if (JNACLibrary.getrlimit(JNACLibrary.RLIMIT_MEMLOCK, rlimit) == 0) { + rlimitSuccess = true; + softLimit = rlimit.rlim_cur; + hardLimit = rlimit.rlim_max; + } else { + logger.warn("Unable to retrieve resource limits: " + JNACLibrary.strerror(Native.getLastError())); } } catch (UnsatisfiedLinkError e) { // this will have already been logged by CLibrary, no need to repeat it return; } - if (errno != Integer.MIN_VALUE) { - if (errno == JNACLibrary.ENOMEM && System.getProperty("os.name").toLowerCase(Locale.ROOT).contains("linux")) { - logger.warn("Unable to lock JVM memory (ENOMEM)." - + " This can result in part of the JVM being swapped out." - + " Increase RLIMIT_MEMLOCK (ulimit)."); - } else if (!System.getProperty("os.name").toLowerCase(Locale.ROOT).contains("mac")) { - // OS X allows mlockall to be called, but always returns an error - logger.warn("Unknown mlockall error " + errno); + // mlockall failed for some reason + logger.warn("Unable to lock JVM Memory: error=" + errno + ",reason=" + errMsg + ". This can result in part of the JVM being swapped out"); + if (errno == JNACLibrary.ENOMEM) { + if (rlimitSuccess) { + logger.warn("Increase RLIMIT_MEMLOCK (ulimit). soft limit:" + softLimit + ", hard limit:" + hardLimit); + } else { + logger.warn("Increase RLIMIT_MEMLOCK (ulimit)."); } } }