Files
2026-04-18 18:41:56 -07:00

221 lines
5.9 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
repo_root="$(cd "${script_dir}/.." && pwd)"
target_dir="${repo_root}/qortal/data"
target_file=""
legacy_default_args='-XX:MaxRAMPercentage=25 -XX:+UseG1GC -Xss1024k'
legacy_autosized_args='-XX:MaxRAMPercentage=66 -XX:+UseG1GC -Xss1024k'
gib_bytes=$((1024 * 1024 * 1024))
env_file=""
seed_args="${QORTAL_JVM_MEMORY_ARGS:-}"
managed_state_file=""
resolve_path() {
local raw="${1:-}"
if [[ -z "${raw}" ]]; then
printf '%s' ""
return 0
fi
if [[ "${raw}" == /* ]]; then
printf '%s' "${raw}"
return 0
fi
printf '%s' "${repo_root}/${raw}"
}
ensure_qortal_data_permissions() {
local data_dir="${1:-}"
if [[ "${EUID:-$(id -u)}" -ne 0 ]]; then
return 0
fi
if [[ -z "${data_dir}" || ! -d "${data_dir}" ]]; then
return 0
fi
chown -R 1000:100 "${data_dir}" >/dev/null 2>&1 || true
chmod -R u+rwX,g+rwX "${data_dir}" >/dev/null 2>&1 || true
}
read_host_memory_bytes() {
if [[ -r /proc/meminfo ]]; then
awk '/^MemTotal:/ { print $2 * 1024; exit }' /proc/meminfo 2>/dev/null || true
fi
}
read_cgroup_memory_bytes() {
local cgroup_file=""
local value=""
for cgroup_file in /sys/fs/cgroup/memory.max /sys/fs/cgroup/memory/memory.limit_in_bytes; do
[[ -r "${cgroup_file}" ]] || continue
value="$(tr -d '\r\n' < "${cgroup_file}" 2>/dev/null || true)"
case "${value}" in
""|"max")
continue
;;
esac
if [[ "${value}" =~ ^[0-9]+$ ]] && [[ "${value}" -gt 0 ]]; then
printf '%s' "${value}"
return 0
fi
done
return 1
}
resolve_available_memory_bytes() {
local host_bytes=""
local cgroup_bytes=""
host_bytes="$(read_host_memory_bytes)"
cgroup_bytes="$(read_cgroup_memory_bytes || true)"
if [[ -n "${host_bytes}" && "${host_bytes}" -gt 0 ]]; then
if [[ -n "${cgroup_bytes}" && "${cgroup_bytes}" -gt 0 && "${cgroup_bytes}" -lt "${host_bytes}" ]]; then
printf '%s' "${cgroup_bytes}"
return 0
fi
printf '%s' "${host_bytes}"
return 0
fi
if [[ -n "${cgroup_bytes}" && "${cgroup_bytes}" -gt 0 ]]; then
printf '%s' "${cgroup_bytes}"
return 0
fi
return 1
}
compute_auto_qortal_args() {
local total_bytes=""
local target_bytes=""
local percentage=""
total_bytes="$(resolve_available_memory_bytes || true)"
if [[ -z "${total_bytes}" || "${total_bytes}" -le 0 ]]; then
printf '%s' "${legacy_autosized_args}"
return 0
fi
target_bytes=$(( total_bytes * 66 / 100 ))
if [[ "${total_bytes}" -ge $((6 * gib_bytes)) ]]; then
if [[ "${target_bytes}" -lt $((4 * gib_bytes)) ]]; then
target_bytes=$((4 * gib_bytes))
fi
if [[ "${target_bytes}" -gt $((8 * gib_bytes)) ]]; then
target_bytes=$((8 * gib_bytes))
fi
fi
percentage="$(awk -v target="${target_bytes}" -v total="${total_bytes}" 'BEGIN { if (total <= 0) { print "66"; exit } printf "%.2f", (target / total) * 100 }')"
printf '%s' "-XX:MaxRAMPercentage=${percentage} -XX:+UseG1GC -Xss1024k"
}
while [[ $# -gt 0 ]]; do
case "$1" in
--target-dir)
target_dir="${2:-}"
shift 2
;;
--target-dir=*)
target_dir="${1#*=}"
shift
;;
--target-file)
target_file="${2:-}"
shift 2
;;
--target-file=*)
target_file="${1#*=}"
shift
;;
-h|--help)
cat <<USAGE
Usage: ./scripts/ensure-qortal-start-args.sh [options] [env-file]
Initialize a Qortal node start-arguments.txt file.
Options:
--target-dir <path> Start args directory (default: ${repo_root}/qortal/data)
--target-file <path> Start args file path override
env-file Optional env file whose QORTAL_JVM_MEMORY_ARGS value overrides auto-sizing
-h, --help Show this help
USAGE
exit 0
;;
*)
if [[ -z "${env_file}" ]]; then
env_file="${1}"
shift
else
echo "Unknown argument: $1" >&2
exit 1
fi
;;
esac
done
target_dir="$(resolve_path "${target_dir}")"
if [[ -z "${target_file}" ]]; then
target_file="${target_dir%/}/start-arguments.txt"
else
target_file="$(resolve_path "${target_file}")"
target_dir="$(dirname "${target_file}")"
fi
managed_state_file="${target_file}.mode"
if [[ -n "${env_file}" && -f "${env_file}" ]]; then
if [[ "${env_file}" != /* ]]; then
env_file="$(resolve_path "${env_file}")"
fi
value_from_env_file="$(grep -E '^QORTAL_JVM_MEMORY_ARGS=' "${env_file}" | tail -n1 | cut -d= -f2- || true)"
if [[ -n "${value_from_env_file}" ]]; then
seed_args="${value_from_env_file}"
fi
fi
mkdir -p "${target_dir}"
ensure_qortal_data_permissions "${target_dir}"
auto_args="$(compute_auto_qortal_args)"
existing_args=""
existing_mode=""
if [[ -f "${target_file}" && -s "${target_file}" ]]; then
existing_args="$(tr -d '\r' < "${target_file}" | sed 's/[[:space:]]*$//')"
fi
if [[ -f "${managed_state_file}" && -s "${managed_state_file}" ]]; then
existing_mode="$(tr -d '\r' < "${managed_state_file}" | sed 's/[[:space:]]*$//')"
fi
if [[ -n "${seed_args}" ]]; then
printf '%s\n' "${seed_args}" > "${target_file}"
printf '%s\n' "manual" > "${managed_state_file}"
if [[ "${existing_args}" == "${seed_args}" ]]; then
echo "Using Qortal JVM start args from env: ${target_file}"
else
echo "Updated Qortal JVM start args from env: ${target_file}"
fi
exit 0
fi
if [[ -f "${target_file}" && -s "${target_file}" ]]; then
if [[ "${existing_mode}" == "auto" || "${existing_args}" == "${legacy_default_args}" || "${existing_args}" == "${legacy_autosized_args}" ]]; then
printf '%s\n' "${auto_args}" > "${target_file}"
printf '%s\n' "auto" > "${managed_state_file}"
echo "Updated auto-sized Qortal JVM start args: ${target_file}"
exit 0
fi
echo "Using existing Qortal JVM start args: ${target_file}"
exit 0
fi
printf '%s\n' "${auto_args}" > "${target_file}"
printf '%s\n' "auto" > "${managed_state_file}"
echo "Initialized auto-sized Qortal JVM start args: ${target_file}"