All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.elasticsearch.nativeaccess.PosixNativeAccess Maven / Gradle / Ivy

There is a newer version: 8.17.0
Show newest version
/*
 * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
 * or more contributor license agreements. Licensed under the Elastic License
 * 2.0 and the Server Side Public License, v 1; you may not use this file except
 * in compliance with, at your election, the Elastic License 2.0 or the Server
 * Side Public License, v 1.
 */

package org.elasticsearch.nativeaccess;

import org.elasticsearch.nativeaccess.lib.NativeLibraryProvider;
import org.elasticsearch.nativeaccess.lib.PosixCLibrary;
import org.elasticsearch.nativeaccess.lib.VectorLibrary;

import java.util.Optional;

abstract class PosixNativeAccess extends AbstractNativeAccess {

    public static final int MCL_CURRENT = 1;
    public static final int ENOMEM = 12;

    protected final PosixCLibrary libc;
    protected final VectorSimilarityFunctions vectorDistance;
    protected final PosixConstants constants;
    protected final ProcessLimits processLimits;

    PosixNativeAccess(String name, NativeLibraryProvider libraryProvider, PosixConstants constants) {
        super(name, libraryProvider);
        this.libc = libraryProvider.getLibrary(PosixCLibrary.class);
        this.vectorDistance = vectorSimilarityFunctionsOrNull(libraryProvider);
        this.constants = constants;
        this.processLimits = new ProcessLimits(
            getMaxThreads(),
            getRLimit(constants.RLIMIT_AS(), "max size virtual memory"),
            getRLimit(constants.RLIMIT_FSIZE(), "max file size")
        );
    }

    /**
     * Return the maximum number of threads this process may start, or {@link ProcessLimits#UNKNOWN}.
     */
    protected abstract long getMaxThreads();

    /**
     * Return the current rlimit for the given resource.
     * If getrlimit fails, returns {@link ProcessLimits#UNKNOWN}.
     * If the rlimit is unlimited, returns {@link ProcessLimits#UNLIMITED}.
     * */
    protected long getRLimit(int resource, String description) {
        var rlimit = libc.newRLimit();
        if (libc.getrlimit(resource, rlimit) == 0) {
            long value = rlimit.rlim_cur();
            return value == constants.RLIMIT_INFINITY() ? ProcessLimits.UNLIMITED : value;
        } else {
            logger.warn("unable to retrieve " + description + " [" + libc.strerror(libc.errno()) + "]");
            return ProcessLimits.UNKNOWN;
        }
    }

    static VectorSimilarityFunctions vectorSimilarityFunctionsOrNull(NativeLibraryProvider libraryProvider) {
        if (isNativeVectorLibSupported()) {
            var lib = libraryProvider.getLibrary(VectorLibrary.class).getVectorSimilarityFunctions();
            logger.info("Using native vector library; to disable start with -D" + ENABLE_JDK_VECTOR_LIBRARY + "=false");
            return lib;
        }
        return null;
    }

    @Override
    public boolean definitelyRunningAsRoot() {
        return libc.geteuid() == 0;
    }

    @Override
    public ProcessLimits getProcessLimits() {
        return processLimits;
    }

    @Override
    public void tryLockMemory() {
        int result = libc.mlockall(MCL_CURRENT);
        if (result == 0) {
            isMemoryLocked = true;
            return;
        }

        // mlockall failed for some reason
        int errno = libc.errno();
        String errMsg = libc.strerror(errno);
        logger.warn("Unable to lock JVM Memory: error={}, reason={}", errno, errMsg);
        logger.warn("This can result in part of the JVM being swapped out.");

        if (errno == ENOMEM) {

            boolean rlimitSuccess = false;
            long softLimit = 0;
            long hardLimit = 0;

            // we only know RLIMIT_MEMLOCK for these two at the moment.
            var rlimit = libc.newRLimit();
            if (libc.getrlimit(constants.RLIMIT_MEMLOCK(), rlimit) == 0) {
                rlimitSuccess = true;
                softLimit = rlimit.rlim_cur();
                hardLimit = rlimit.rlim_max();
            } else {
                logger.warn("Unable to retrieve resource limits: {}", libc.strerror(libc.errno()));
            }

            if (rlimitSuccess) {
                logger.warn(
                    "Increase RLIMIT_MEMLOCK, soft limit: {}, hard limit: {}",
                    rlimitToString(softLimit),
                    rlimitToString(hardLimit)
                );
                logMemoryLimitInstructions();
            } else {
                logger.warn("Increase RLIMIT_MEMLOCK (ulimit).");
            }
        }
    }

    protected abstract void logMemoryLimitInstructions();

    @Override
    public Optional getVectorSimilarityFunctions() {
        return Optional.ofNullable(vectorDistance);
    }

    String rlimitToString(long value) {
        if (value == constants.RLIMIT_INFINITY()) {
            return "unlimited";
        } else {
            return Long.toUnsignedString(value);
        }
    }

    static boolean isNativeVectorLibSupported() {
        return Runtime.version().feature() >= 21 && (isMacOrLinuxAarch64() || isLinuxAmd64()) && checkEnableSystemProperty();
    }

    /**
     * Returns true iff the architecture is x64 (amd64) and the OS Linux (the OS we currently support for the native lib).
     */
    static boolean isLinuxAmd64() {
        String name = System.getProperty("os.name");
        return (name.startsWith("Linux")) && System.getProperty("os.arch").equals("amd64");
    }

    /** Returns true iff the OS is Mac or Linux, and the architecture is aarch64. */
    static boolean isMacOrLinuxAarch64() {
        String name = System.getProperty("os.name");
        return (name.startsWith("Mac") || name.startsWith("Linux")) && System.getProperty("os.arch").equals("aarch64");
    }

    /** -Dorg.elasticsearch.nativeaccess.enableVectorLibrary=false to disable.*/
    static final String ENABLE_JDK_VECTOR_LIBRARY = "org.elasticsearch.nativeaccess.enableVectorLibrary";

    static boolean checkEnableSystemProperty() {
        return Optional.ofNullable(System.getProperty(ENABLE_JDK_VECTOR_LIBRARY)).map(Boolean::valueOf).orElse(Boolean.TRUE);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy