#!/usr/bin/env bash # Absolute DB v9.5.1 # Copyright (c) 2024-2026 D.H.Maree. All rights reserved. # Author/Creator: David H Maree # Owner: D.H.Maree (ABN 21 498 105 915) — sole IP holder # Licensed to: SupportCALL AU — primary distributor # SPDX-License-Identifier: BSL-1.1 # https://absolutedb.com/ # https://downloads.absolutedb.com/install-arm64.sh # # Supported platforms: # Raspberry Pi OS Bookworm (64-bit), Bullseye (64-bit), Buster (64-bit) # Ubuntu 22.04 LTS (Jammy), 24.04 LTS (Noble) — ARM64 # Debian 11 (Bullseye), 12 (Bookworm) — ARM64 # Orange Pi, Rock Pi, Radxa, Banana Pi (any Debian/Ubuntu-based ARM64 OS) # # Note: For best performance, use a 64-bit OS (aarch64). 32-bit (armv7l) is # supported but runs without NEON SIMD optimisations. # # Usage: # bash install-arm64.sh # bash install-arm64.sh --no-service # skip systemd service setup # bash install-arm64.sh --no-test # skip post-build test suite # bash install-arm64.sh --uninstall # remove Absolute DB # bash install-arm64.sh --prefix=/opt/absdb # custom install prefix # bash install-arm64.sh --branch=master # checkout specific branch # # Copyright 2024-2026 SupportCALL AU & D.H.Maree # SPDX-License-Identifier: BSL-1.1 set -euo pipefail # ── Constants ───────────────────────────────────────────────────────────────── VERSION="9.5.1" REPO="https://github.com/supportcall/AbsoluteDB.git" INSTALL_DIR="${HOME}/AbsoluteDB" DATA_DIR="/var/lib/absdb" LOG_DIR="/var/log/absdb" PG_PORT=5433 REST_PORT=8080 GRPC_PORT=9090 SERVICE_NAME="absdb" SERVICE_USER="absdb" CONF_DIR="/etc/absdb" CONF_FILE="/etc/absdb/absdb.conf" SWAP_FILE="/swapfile-absdb" SWAP_SIZE_MB=1024 LOG_FILE="/tmp/absdb-install-$$.log" # ── Colour helpers ──────────────────────────────────────────────────────────── GRN='\033[0;32m'; BLU='\033[0;34m'; YLW='\033[0;33m' RED='\033[0;31m'; CYN='\033[0;36m'; NC='\033[0m'; BOLD='\033[1m' info() { echo -e "${BLU}[INFO]${NC} $*"; } ok() { echo -e "${GRN}[ OK ]${NC} $*"; } warn() { echo -e "${YLW}[WARN]${NC} $*"; } step() { echo -e "\n${BOLD}${CYN}$*${NC}"; } die() { echo -e "\n${RED}${BOLD}[FAIL]${NC} $*" >&2 echo -e "${YLW}${BOLD}Troubleshooting guide:${NC}" >&2 echo -e " 1. Full install log: ${LOG_FILE}" >&2 echo -e " 2. Re-run with verbose output: bash -x install-arm64.sh" >&2 echo -e " 3. 32-bit vs 64-bit: check with: uname -m (want aarch64)" >&2 echo -e " Upgrade to 64-bit Raspberry Pi OS for best performance." >&2 echo -e " 4. Swap too low? Check: free -h" >&2 echo -e " Script auto-creates swap if RAM < 1 GB." >&2 echo -e " 5. SD card too slow? Build may timeout on slow cards." >&2 echo -e " Use a fast A2-rated SD card or USB SSD." >&2 echo -e " 6. Package install failed? Try: sudo apt-get update --fix-missing" >&2 echo -e " 7. Overheating? Check: vcgencmd measure_temp" >&2 echo -e " Use heatsink/fan for sustained compilation." >&2 echo -e " 8. Port ${PG_PORT} in use? Check: ss -tlnp | grep ${PG_PORT}" >&2 echo -e " 9. systemd service failed? Check: journalctl -u ${SERVICE_NAME} -n 50" >&2 echo -e " 10. Permissions on ${DATA_DIR}? Check: ls -la /var/lib/absdb" >&2 echo -e " 11. See full docs: https://absolutedb.com/docs/install-arm64" >&2 exit 1 } # Redirect all output to log file while keeping terminal output exec > >(tee -a "${LOG_FILE}") 2>&1 # ── Require root for system install ─────────────────────────────────────────── if [ "$(id -u)" -ne 0 ]; then echo "" echo " This installer requires root to install system binaries and create a" echo " system service. It will now re-run under sudo." echo " Review the script first: https://downloads.absolutedb.com/install-arm64.sh" echo "" # When piped via curl|bash, $0 is "bash" or "/dev/stdin" — re-exec is impossible. # Detect this and instruct the user to save the script first. if [ "$0" = "bash" ] || [ "$0" = "/dev/stdin" ] || [ "$0" = "-" ]; then echo " ERROR: Cannot re-exec when piped directly from curl." echo " Please save the script and run it as root:" echo " curl -fsSL https://downloads.absolutedb.com/install-arm64.sh -o install-arm64.sh" echo " sudo bash install-arm64.sh" exit 1 fi exec sudo bash "$0" "$@" fi # ── Argument parsing ────────────────────────────────────────────────────────── OPT_NO_SERVICE=0 OPT_NO_TEST=0 OPT_UNINSTALL=0 BRANCH="main" BIN_PREFIX="" for a in "$@"; do case "$a" in --no-service) OPT_NO_SERVICE=1 ;; --no-test) OPT_NO_TEST=1 ;; --uninstall) OPT_UNINSTALL=1 ;; --prefix=*) BIN_PREFIX="${a#--prefix=}" ;; --branch=*) BRANCH="${a#--branch=}" ;; --help|-h) echo "Usage: bash install-arm64.sh [OPTIONS]" echo " --no-service Skip systemd service setup" echo " --no-test Skip post-build test suite" echo " --uninstall Remove Absolute DB" echo " --prefix= Install binaries to /bin (default: /usr/local)" echo " --branch= Git branch to install (default: main)" exit 0 ;; *) warn "Unknown option: $a (ignored)" ;; esac done BIN_PREFIX="${BIN_PREFIX:-/usr/local}" BIN_DIR="${BIN_PREFIX}/bin" # ── Detect architecture ──────────────────────────────────────────────────────── ARCH=$(uname -m) IS_64BIT=0 IS_RPI=0 PI_MODEL="Unknown" if [ "${ARCH}" = "aarch64" ] || [ "${ARCH}" = "arm64" ]; then IS_64BIT=1 fi if grep -q "Raspberry Pi" /proc/cpuinfo 2>/dev/null; then IS_RPI=1 PI_MODEL=$(grep "Model" /proc/cpuinfo 2>/dev/null | head -1 | cut -d: -f2 | xargs || echo "Raspberry Pi (model unknown)") fi # Detect OS distribution OS_ID="unknown" OS_VERSION="unknown" if [ -f /etc/os-release ]; then . /etc/os-release OS_ID="${ID:-unknown}" OS_VERSION="${VERSION_ID:-unknown}" fi # ── Banner ──────────────────────────────────────────────────────────────────── echo "" echo -e "${BOLD}${GRN}╔══════════════════════════════════════════════════════════╗${NC}" echo -e "${BOLD}${GRN}║ Absolute DB v${VERSION} — ARM64 Installer ║${NC}" echo -e "${BOLD}${GRN}╚══════════════════════════════════════════════════════════╝${NC}" echo "" echo -e " Architecture : ${BOLD}${ARCH}${NC} ($([ "${IS_64BIT}" -eq 1 ] && echo "64-bit — full NEON SIMD" || echo "32-bit — limited SIMD"))" if [ "${IS_RPI}" -eq 1 ]; then echo -e " Hardware : ${BOLD}${PI_MODEL}${NC}" fi echo -e " OS : ${BOLD}${OS_ID} ${OS_VERSION}${NC}" echo -e " Install : ${BOLD}${INSTALL_DIR}${NC}" echo -e " Binaries : ${BOLD}${BIN_DIR}${NC}" echo -e " Data : ${BOLD}${DATA_DIR}${NC}" echo -e " Branch : ${BOLD}${BRANCH}${NC}" echo -e " Log : ${BOLD}${LOG_FILE}${NC}" echo "" if [ "${IS_64BIT}" -eq 0 ]; then # armv6 (Pi Zero, Pi 1) is not supported — the build will fail at compile time # without a helpful error. Hard-stop here with clear guidance. if echo "${ARCH}" | grep -qE "^armv6"; then echo "" echo " ERROR: armv6 (${ARCH}) is not supported by this installer." echo " Absolute DB v${VERSION} requires a 64-bit ARMv8 (aarch64) processor." echo "" echo " Raspberry Pi Zero / Pi Zero W / Pi 1 / Pi 2 (armv6/armv7) are not supported." echo " Supported: Raspberry Pi 3B+, 4, 5 running 64-bit OS." echo "" echo " Upgrade guide: https://www.raspberrypi.com/software/" exit 1 fi # armv7 — warn clearly that the build may fail on this architecture if echo "${ARCH}" | grep -qE "^armv7"; then warn "armv7 detected. Absolute DB v${VERSION} compiles on armv7 but runs" warn "without NEON SIMD optimisations and build may fail with limited RAM." warn "If the build fails, use the Docker installer instead:" warn " bash <(curl -fsSL https://downloads.absolutedb.com/install-docker.sh)" else warn "You are running a 32-bit OS (${ARCH}) on a 64-bit capable CPU." warn "For 2-4x better performance, upgrade to 64-bit Raspberry Pi OS:" warn " https://www.raspberrypi.com/software/" fi echo "" fi if [ "${IS_RPI}" -eq 1 ] && [ "${IS_64BIT}" -eq 1 ]; then ok "64-bit Raspberry Pi OS detected — NEON SIMD acceleration enabled" fi # ── Uninstall ───────────────────────────────────────────────────────────────── if [ "${OPT_UNINSTALL}" -eq 1 ]; then step "Uninstalling Absolute DB v${VERSION}..." systemctl stop "${SERVICE_NAME}" 2>/dev/null || true systemctl disable "${SERVICE_NAME}" 2>/dev/null || true rm -f "/etc/systemd/system/${SERVICE_NAME}.service" systemctl daemon-reload 2>/dev/null || true rm -f "${BIN_DIR}/absdb" "${BIN_DIR}/absdb-server" "${BIN_DIR}/absdb-bench" "${BIN_DIR}/adb_admin" rm -rf "${BIN_PREFIX}/include/absdb" "${BIN_PREFIX}/share/doc/absdb" rm -rf "${INSTALL_DIR}" userdel -r "${SERVICE_USER}" 2>/dev/null || true ok "Absolute DB removed." warn "Data in ${DATA_DIR} and logs in ${LOG_DIR} were NOT removed." warn "Remove manually if desired: rm -rf ${DATA_DIR} ${LOG_DIR}" exit 0 fi # ── Step 1/5: System requirements ───────────────────────────────────────────── step "Step 1/5: Checking system requirements" # Show RAM TOTAL_RAM_KB=$(grep MemTotal /proc/meminfo 2>/dev/null | awk '{print $2}' || echo 0) TOTAL_RAM_MB=$(( TOTAL_RAM_KB / 1024 )) AVAIL_RAM_KB=$(grep MemAvailable /proc/meminfo 2>/dev/null | awk '{print $2}' || echo 0) AVAIL_RAM_MB=$(( AVAIL_RAM_KB / 1024 )) info "RAM: ${TOTAL_RAM_MB} MB total, ${AVAIL_RAM_MB} MB available" if [ "${TOTAL_RAM_MB}" -lt 512 ]; then warn "Low RAM detected (${TOTAL_RAM_MB} MB). Compilation may fail without swap." elif [ "${TOTAL_RAM_MB}" -lt 1024 ]; then warn "RAM is ${TOTAL_RAM_MB} MB. Swap will be checked and created if needed." else ok "RAM: ${TOTAL_RAM_MB} MB — sufficient" fi # Check disk space (need at least 1.5 GB for build objects + static lib) AVAIL_DISK_KB=$(df -k "${HOME}" | awk 'NR==2 {print $4}') AVAIL_DISK_MB=$(( AVAIL_DISK_KB / 1024 )) if [ "${AVAIL_DISK_MB}" -lt 1536 ]; then die "Only ${AVAIL_DISK_MB} MB disk space available. Need at least 1.5 GB." else ok "Disk space: ${AVAIL_DISK_MB} MB available" fi # Check/create swap if RAM is < 1 GB SWAP_TOTAL_KB=$(grep SwapTotal /proc/meminfo 2>/dev/null | awk '{print $2}' || echo 0) SWAP_TOTAL_MB=$(( SWAP_TOTAL_KB / 1024 )) if [ "${TOTAL_RAM_MB}" -lt 1024 ] && [ "${SWAP_TOTAL_MB}" -lt 512 ]; then warn "RAM ${TOTAL_RAM_MB} MB + swap ${SWAP_TOTAL_MB} MB is low — creating ${SWAP_SIZE_MB} MB swap file..." if [ -f "${SWAP_FILE}" ]; then warn "Swap file ${SWAP_FILE} already exists — skipping creation" elif [ "${AVAIL_DISK_MB}" -gt $(( SWAP_SIZE_MB + 256 )) ]; then dd if=/dev/zero of="${SWAP_FILE}" bs=1M count="${SWAP_SIZE_MB}" status=progress 2>&1 || \ warn "Could not create swap file — build may fail on very low RAM systems" # Verify the swap file was fully written actual_size_mb=$(( $(stat -c%s "${SWAP_FILE}" 2>/dev/null || echo 0) / 1048576 )) if [ "${actual_size_mb}" -lt "${SWAP_SIZE_MB}" ]; then warn "Swap file smaller than expected (${actual_size_mb} MB vs ${SWAP_SIZE_MB} MB) — disk may be full." rm -f "${SWAP_FILE}" 2>/dev/null || true else chmod 600 "${SWAP_FILE}" mkswap "${SWAP_FILE}" -q swapon "${SWAP_FILE}" ok "Swap file created and activated: ${SWAP_SIZE_MB} MB at ${SWAP_FILE}" fi info "To make swap permanent, add to /etc/fstab:" info " ${SWAP_FILE} none swap sw 0 0" else warn "Not enough disk space to create swap. Build may fail." fi else ok "Memory: ${TOTAL_RAM_MB} MB RAM + ${SWAP_TOTAL_MB} MB swap — sufficient" fi # Raspberry Pi specific hints if [ "${IS_RPI}" -eq 1 ]; then # Check temperature if command -v vcgencmd &>/dev/null; then TEMP=$(vcgencmd measure_temp 2>/dev/null | tr -d "temp=" | tr -d "'C" || echo "?") if [ "$(echo "${TEMP}" | cut -d. -f1)" -ge 75 ] 2>/dev/null; then warn "CPU temperature is ${TEMP}C — high! Ensure adequate cooling during compilation." else ok "CPU temperature: ${TEMP}C" fi fi info "Raspberry Pi tip: For headless server use, disable GUI memory split:" info " sudo raspi-config -> Performance -> GPU Memory -> set to 16" fi # ── Step 2/5: Install prerequisites ────────────────────────────────────────── step "Step 2/5: Installing prerequisites" export DEBIAN_FRONTEND=noninteractive # Only apt-get based distros are supported (Raspberry Pi OS, Debian, Ubuntu ARM64) if ! command -v apt-get >/dev/null 2>&1; then die "This installer requires apt-get (Debian/Ubuntu/Raspberry Pi OS)." \ "For other distributions, use the Docker installer:" \ " bash <(curl -fsSL https://downloads.absolutedb.com/install-docker.sh)" fi info "Updating package lists..." apt-get update -qq || die "apt-get update failed. Check internet connection and /etc/apt/sources.list" PACKAGES="build-essential gcc make git curl ca-certificates netcat-openbsd" info "Installing: ${PACKAGES}" apt-get install -y -qq ${PACKAGES} || die "Package installation failed. Try: sudo apt-get update --fix-missing" # Verify each tool for tool in gcc make git curl; do command -v "${tool}" &>/dev/null || die "${tool} not found after installation" ok "${tool}: $(${tool} --version 2>/dev/null | head -1)" done # ── Branch detection and clone helpers ──────────────────────────────────────── _detect_branch() { local remote="${1:-origin}" if git ls-remote --heads "${remote}" main 2>/dev/null | grep -q "refs/heads/main"; then echo "main" elif git ls-remote --heads "${remote}" master 2>/dev/null | grep -q "refs/heads/master"; then echo "master" else echo "main" fi } _git_clone_with_retry() { local branch="$1" dest="$2" repo="$3" local attempt=1 delay=4 while [ "${attempt}" -le 3 ]; do # Remove any partial clone directory before each attempt if [ -d "${dest}" ] && [ ! -f "${dest}/.git/HEAD" ]; then warn "Removing incomplete directory ${dest} before retry..." rm -rf "${dest}" || true fi if git clone --depth=1 --branch="${branch}" "${repo}" "${dest}" 2>&1; then return 0 fi if [ "${attempt}" -lt 3 ]; then warn "Clone attempt ${attempt}/3 failed — retrying in ${delay}s..." sleep "${delay}"; delay=$(( delay * 2 )) fi attempt=$(( attempt + 1 )) done die "git clone failed after 3 attempts. Check: internet, DNS, firewall, proxy settings." } # ── Step 3/5: Clone and build ────────────────────────────────────────────────── step "Step 3/5: Downloading and building Absolute DB" # Use the invoking user's home if running under sudo BUILD_USER="${SUDO_USER:-root}" BUILD_HOME=$(eval echo "~${BUILD_USER}" 2>/dev/null || echo "${HOME}") INSTALL_DIR="${BUILD_HOME}/AbsoluteDB" # Detect actual branch from remote (prefers 'main') if [ "${BRANCH}" = "main" ]; then _detected="$( _detect_branch "${REPO}" )" [ "${_detected}" != "${BRANCH}" ] && { info "Remote branch detected: ${_detected}"; BRANCH="${_detected}"; } fi if [ -d "${INSTALL_DIR}/.git" ]; then info "Existing installation found — updating..." cd "${INSTALL_DIR}" info "Fetching latest source (branch: ${BRANCH})..." if ! git fetch --depth=1 origin "${BRANCH}" 2>&1; then warn "git fetch failed — removing and recloning from scratch..." cd /; rm -rf "${INSTALL_DIR}" _git_clone_with_retry "${BRANCH}" "${INSTALL_DIR}" "${REPO}" ok "Source recloned to ${INSTALL_DIR}" else # Use FETCH_HEAD — always valid after fetch, works correctly on shallow clones git reset --hard FETCH_HEAD ok "Source updated" fi else [ -d "${INSTALL_DIR}" ] && rm -rf "${INSTALL_DIR}" info "Cloning Absolute DB from GitHub..." _git_clone_with_retry "${BRANCH}" "${INSTALL_DIR}" "${REPO}" ok "Source cloned to ${INSTALL_DIR}" fi chown -R "${BUILD_USER}:${BUILD_USER}" "${INSTALL_DIR}" 2>/dev/null || true cd "${INSTALL_DIR}" # Detect CPU cores for parallel build NPROC=$(nproc 2>/dev/null || echo 1) info "Building with ${NPROC} CPU core(s)..." info "Note: Compilation may take 2-10 minutes on Raspberry Pi — this is normal." # Check available memory and limit parallelism on low-memory hosts TOTAL_MEM_MB_CHECK=$(( ($(awk '/^MemTotal/{print $2}' /proc/meminfo 2>/dev/null || echo 0) + \ $(awk '/^SwapTotal/{print $2}' /proc/meminfo 2>/dev/null || echo 0)) / 1024 )) if [ "${TOTAL_MEM_MB_CHECK}" -lt 1024 ]; then warn "Low memory (${TOTAL_MEM_MB_CHECK} MB RAM+swap). Limiting to single-threaded build." NPROC=1 fi # Build as the regular user for safety if [ "${BUILD_USER}" != "root" ]; then su -c "cd '${INSTALL_DIR}' && make clean -s 2>/dev/null || true && make release -j${NPROC}" - "${BUILD_USER}" || \ die "Build failed. Check output above. SD card speed, RAM, or temperature may be the cause." else make clean -s 2>/dev/null || true make release -j"${NPROC}" || \ die "Build failed. Check output above." fi # Verify mandatory build artifacts [ -x "${INSTALL_DIR}/build/absdb" ] || [ -x "${INSTALL_DIR}/bin/absdb" ] || \ die "absdb binary not found after build. Build may have failed silently." [ -x "${INSTALL_DIR}/build/absdb-server" ] || [ -x "${INSTALL_DIR}/bin/absdb-server" ] || \ die "absdb-server binary not found after build. Build may have failed silently." # Optional binaries [ -x "${INSTALL_DIR}/build/adb_admin" ] || [ -x "${INSTALL_DIR}/bin/adb_admin" ] || \ warn "adb_admin not found — protocol management CLI will not be installed" ok "Build complete" # Run tests (unless --no-test) if [ "${OPT_NO_TEST}" -eq 0 ]; then info "Running test suite (may take 1-2 minutes on Raspberry Pi)..." if [ "${BUILD_USER}" != "root" ]; then su -c "cd '${INSTALL_DIR}' && make test" "${BUILD_USER}" 2>&1 | tail -5 || \ warn "Some tests reported failures — check output above" else make test 2>&1 | tail -5 || warn "Some tests reported failures" fi ok "Test suite complete" else info "Test suite skipped (--no-test)" fi # Install binaries info "Installing binaries to ${BIN_DIR}..." mkdir -p "${BIN_DIR}" install -m 755 "${INSTALL_DIR}/build/absdb" "${BIN_DIR}/absdb" install -m 755 "${INSTALL_DIR}/build/absdb-server" "${BIN_DIR}/absdb-server" install -m 755 "${INSTALL_DIR}/build/absdb-bench" "${BIN_DIR}/absdb-bench" 2>/dev/null || true install -m 755 "${INSTALL_DIR}/build/adb_admin" "${BIN_DIR}/adb_admin" 2>/dev/null || true # Install headers and docs mkdir -p "${BIN_PREFIX}/include/absdb" "${BIN_PREFIX}/share/doc/absdb" cp "${INSTALL_DIR}/include/absolute.h" "${INSTALL_DIR}/include/adb_types.h" \ "${BIN_PREFIX}/include/absdb/" 2>/dev/null || true cp "${INSTALL_DIR}/README.md" "${INSTALL_DIR}/LICENSE" \ "${BIN_PREFIX}/share/doc/absdb/" 2>/dev/null || true # Verify installed binaries "${BIN_DIR}/absdb" --version &>/dev/null || warn "absdb --version check failed" "${BIN_DIR}/absdb-server" --version &>/dev/null || warn "absdb-server --version check failed" if [ -x "${BIN_DIR}/adb_admin" ]; then ok "Binaries installed and verified: ${BIN_DIR}/absdb, ${BIN_DIR}/absdb-server, ${BIN_DIR}/adb_admin" else ok "Binaries installed and verified: ${BIN_DIR}/absdb, ${BIN_DIR}/absdb-server" warn "adb_admin not installed — protocol management requires rebuilding with make all" fi # ── Step 4/5: Create service user and data directories ──────────────────────── step "Step 4/5: Creating service user and data directories" if ! id "${SERVICE_USER}" &>/dev/null; then useradd --system --no-create-home --shell /usr/sbin/nologin "${SERVICE_USER}" || \ warn "Could not create service user ${SERVICE_USER} — will run as current user" ok "Service user created: ${SERVICE_USER}" else ok "Service user already exists: ${SERVICE_USER}" fi mkdir -p "${DATA_DIR}" "${LOG_DIR}" if id "${SERVICE_USER}" >/dev/null 2>&1; then chown "${SERVICE_USER}:${SERVICE_USER}" "${DATA_DIR}" "${LOG_DIR}" 2>/dev/null || true else warn "Service user '${SERVICE_USER}' does not exist — skipping chown of data/log dirs." fi chmod 750 "${DATA_DIR}" "${LOG_DIR}" ok "Data directory: ${DATA_DIR}" ok "Log directory: ${LOG_DIR}" # ── Protocol wizard + config file ──────────────────────────────────────────── if [ -t 0 ] && [ -t 1 ]; then echo "" echo -e " ${BOLD}Adaptive Protocol Manager — select which ports to open${NC}" echo -e " ${DIM}Only enabled protocols open ports (least-protocol principle).${NC}" echo "" echo -e " ${CYN}1)${NC} Minimal — PostgreSQL wire + REST ${DIM}(default, most secure)${NC}" echo -e " ${CYN}2)${NC} Web App — + Redis (sessions/caching)" echo -e " ${CYN}3)${NC} Microservices — + gRPC" echo -e " ${CYN}4)${NC} Enterprise — All protocols" echo "" read -rp " Protocol preset [1-4, default=1]: " _proto_choice _proto_choice="${_proto_choice:-1}" case "${_proto_choice}" in 2) _grpc=off; _redis=on; _prometheus=off ;; 3) _grpc=on; _redis=off; _prometheus=off ;; 4) _grpc=on; _redis=on; _prometheus=on ;; *) _grpc=off; _redis=off; _prometheus=off ;; esac else warn "Non-interactive — applying Minimal preset (pg_wire + rest)." warn "Re-run wizard: ${BIN_DIR}/absdb-server --setup" _grpc=off; _redis=off; _prometheus=off fi mkdir -p "${CONF_DIR}" cat > "${CONF_FILE}" </dev/null || true chmod 640 "${CONF_FILE}" ok "Config written: ${CONF_FILE}" echo -e " ${DIM}Change later: adb_admin --protocol enable ${NC}" # ── Step 5/5: systemd service ───────────────────────────────────────────────── step "Step 5/5: Service setup" if [ "${OPT_NO_SERVICE}" -eq 0 ] && command -v systemctl &>/dev/null; then info "Creating systemd service: ${SERVICE_NAME}" cat > "/etc/systemd/system/${SERVICE_NAME}.service" </dev/null | grep -qE ":${_port}[[:space:]]|:${_port}$") 2>/dev/null || \ (netstat -tlnp 2>/dev/null | grep -qE ":${_port}[[:space:]]|:${_port}$") 2>/dev/null; then _port_in_use=true fi if [ "${_port_in_use}" = true ]; then warn "Port ${_port} is already in use — service may fail to start." warn "Check with: ss -tlnp | grep :${_port}" fi done systemctl start "${SERVICE_NAME}" || die "Service failed to start. Check: journalctl -u ${SERVICE_NAME} -n 50" # Wait for service to be active info "Waiting for service to start..." STARTED=0 for i in $(seq 1 20); do sleep 1 if systemctl is-active --quiet "${SERVICE_NAME}"; then ok "Service ${SERVICE_NAME} is running" STARTED=1 break fi done if [ "${STARTED}" -eq 0 ]; then warn "Service did not become active within 20 seconds." warn " Check logs: journalctl -u ${SERVICE_NAME} -n 50 --no-pager" warn " Port in use? ss -tlnp | grep ${PG_PORT}" fi # Check if it crashed immediately after appearing active sleep 1 if systemctl is-failed --quiet "${SERVICE_NAME}" 2>/dev/null; then warn "${SERVICE_NAME} entered failed state." journalctl -u "${SERVICE_NAME}" -n 30 --no-pager 2>/dev/null || true fi elif [ "${OPT_NO_SERVICE}" -eq 0 ]; then warn "systemd not available — skipping service setup" info "To start manually: ${BIN_DIR}/absdb-server -c ${CONF_FILE}" else info "Service setup skipped (--no-service)" info "To start manually: ${BIN_DIR}/absdb-server -c ${CONF_FILE}" fi # ── Health check ───────────────────────────────────────────────────────────── if [ "${OPT_NO_SERVICE}" -eq 0 ]; then echo "" info "Testing REST API health endpoint..." REST_OK=0 for i in $(seq 1 10); do sleep 1 HEALTH=$(curl -sf --connect-timeout 2 "http://localhost:${REST_PORT}/health" 2>/dev/null || true) if echo "${HEALTH}" | grep -q '"status"'; then ok "REST API healthy: ${HEALTH}" REST_OK=1 break fi done [ "${REST_OK}" -eq 0 ] && warn "REST API did not respond. Check: journalctl -u ${SERVICE_NAME} -n 30" fi # ── Performance note ────────────────────────────────────────────────────────── echo "" echo -e "${BOLD} ARM64 Performance Notes:${NC}" if [ "${IS_64BIT}" -eq 1 ]; then echo " - NEON SIMD acceleration: ENABLED (64-bit OS)" echo " - Expected performance vs x86-64 reference: ~60-85%" if [ "${IS_RPI}" -eq 1 ]; then echo " - Raspberry Pi 4/5 with fast storage (NVMe/USB SSD): ~50K-150K INSERT/sec" echo " - Raspberry Pi 4/5 with SD card: ~10K-30K INSERT/sec (I/O limited)" fi else echo " - NEON SIMD: DISABLED (32-bit OS) — upgrade to 64-bit OS for 2-4x speedup" fi echo "" # ── Production vs Testing wizard ───────────────────────────────────────────── if [ -t 0 ] && [ -t 1 ]; then echo "" echo -e " ${BOLD}Is this installation for Production or Testing/Evaluation?${NC}" echo "" echo -e " ${BOLD}${RED}┌─────────────────────────────────────────────────────────────────┐${NC}" echo -e " ${BOLD}${RED}│${NC} ${CYN}1)${NC} ${BOLD}Production${NC} — clean start, no sample data ${BOLD}${RED}│${NC}" echo -e " ${BOLD}${RED}│${NC} ${CYN}2)${NC} ${BOLD}Testing${NC} — optionally load tier-sized sample data ${BOLD}${RED}│${NC}" echo -e " ${BOLD}${RED}└─────────────────────────────────────────────────────────────────┘${NC}" echo "" INSTALL_TYPE="" while true; do read -rp " Enter choice [1/2] (default: 1): " _it _it="${_it:-1}" case "${_it}" in 1|production|prod) INSTALL_TYPE="production"; break ;; 2|testing|test) INSTALL_TYPE="testing"; break ;; *) echo " Enter 1 or 2." ;; esac done if [ "${INSTALL_TYPE}" = "testing" ]; then echo "" read -rp " Generate sample/test data now? [y/N]: " _wd _wd="${_wd:-n}" if [[ "${_wd,,}" == "y" || "${_wd,,}" == "yes" ]]; then echo "" echo -e " ${BOLD}Select tier size:${NC}" echo "" echo -e " ${CYN}1)${NC} Community — ${YLW}2 GB${NC}" echo -e " ${CYN}2)${NC} SME — ${YLW}3 GB${NC}" echo -e " ${CYN}3)${NC} Professional — ${YLW}10 GB${NC}" echo -e " ${CYN}4)${NC} Enterprise — ${YLW}20 GB${NC}" echo "" DATA_TIER="" while true; do read -rp " Enter tier [1-4 or name]: " _dt _dt="${_dt,,}" case "${_dt}" in 1|community) DATA_TIER="community"; break ;; 2|sme) DATA_TIER="sme"; break ;; 3|pro|professional) DATA_TIER="pro"; break ;; 4|enterprise) DATA_TIER="enterprise"; break ;; *) echo " Enter 1–4 or community/sme/pro/enterprise." ;; esac done GEN_SH="${INSTALL_DIR:-${HOME}/AbsoluteDB}/tools/gen_test_data.sh" GEN_PY="${INSTALL_DIR:-${HOME}/AbsoluteDB}/tools/gen_test_data.py" if [ -f "${GEN_SH}" ]; then bash "${GEN_SH}" --tier "${DATA_TIER}" --host 127.0.0.1 \ --port "${PG_PORT:-5433}" --dbname absdb --drop-existing \ || echo "[WARN] Sample data generation encountered errors." elif [ -f "${GEN_PY}" ] && command -v python3 &>/dev/null; then python3 -c "import psycopg2" &>/dev/null 2>&1 \ || python3 -m pip install --quiet psycopg2-binary python3 "${GEN_PY}" --tier "${DATA_TIER}" --host 127.0.0.1 \ --port "${PG_PORT:-5433}" --dbname absdb --drop-existing \ || echo "[WARN] Sample data generation encountered errors." else echo "[WARN] gen_test_data.sh not found. Run later:" echo " bash ${GEN_SH} --tier ${DATA_TIER}" fi fi else echo " Production install — no sample data loaded." echo " To generate test data later: bash tools/gen_test_data.sh" fi fi # ── Final summary ───────────────────────────────────────────────────────────── echo -e "${BOLD}${GRN}╔══════════════════════════════════════════════════════════╗${NC}" echo -e "${BOLD}${GRN}║ Absolute DB v${VERSION} installed successfully! ║${NC}" echo -e "${BOLD}${GRN}╚══════════════════════════════════════════════════════════╝${NC}" echo "" echo -e "${BOLD} Quick start:${NC}" echo "" echo -e " ${CYN}REST API:${NC}" echo " curl http://localhost:${REST_PORT}/health" echo " curl -X POST http://localhost:${REST_PORT}/sql \\" echo " -H 'Content-Type: application/json' \\" echo " -d '{\"sql\":\"SELECT 1+1 AS result\"}'" echo "" echo -e " ${CYN}PostgreSQL wire:${NC}" echo " psql -h localhost -p ${PG_PORT}" echo "" echo -e " ${CYN}CLI:${NC}" echo " absdb # interactive shell" echo " absdb -c \"SELECT version()\" # single query" echo "" echo -e " ${CYN}Service management:${NC}" echo " systemctl status ${SERVICE_NAME} # check status" echo " systemctl stop ${SERVICE_NAME} # stop" echo " systemctl start ${SERVICE_NAME} # start" echo " systemctl restart ${SERVICE_NAME} # restart" echo " journalctl -u ${SERVICE_NAME} -f # follow logs" echo "" echo -e "${BOLD} Next steps:${NC}" echo "" echo -e " ${YLW}1. Open firewall ports for remote access:${NC}" echo -e " ${CYN}sudo ufw allow ${PG_PORT}/tcp${NC} ${DIM}# PostgreSQL wire protocol${NC}" echo -e " ${CYN}sudo ufw allow ${REST_PORT}/tcp${NC} ${DIM}# REST API + Web console${NC}" echo -e " ${CYN}sudo ufw allow ${GRPC_PORT}/tcp${NC} ${DIM}# gRPC / HTTP/2${NC}" echo -e " ${CYN}sudo ufw allow 6379/tcp${NC} ${DIM}# Redis RESP3 (if enabled)${NC}" echo "" echo -e " ${YLW}2. Open the web management console:${NC}" echo -e " ${CYN}http://localhost:${REST_PORT}/console${NC}" echo "" echo -e " ${YLW}3. Enable TLS for production:${NC}" echo -e " See ${DIM}https://absolutedb.com/docs/tls${NC}" echo "" echo -e " ${CYN}Data:${NC} ${DATA_DIR}" echo -e " ${CYN}Logs:${NC} journalctl -u ${SERVICE_NAME}" echo -e " ${CYN}Uninstall:${NC} bash install-arm64.sh --uninstall" echo "" echo -e " ${CYN}Docs:${NC} https://absolutedb.com/docs/arm64" echo -e " ${CYN}Support:${NC} https://absolutedb.com/support" echo ""