#!/bin/bash

# --------------------------------------------------------------------------
#                          OceanBase Copyright@2020
#                         https://www.oceanbase.com/
# ---------------------------------------------------------------------------
# Set JAVA_HOME or JRE_HOME if not already set, ensure any provided settings
# are valid and consistent with the selected start-up options and set up the
# endorsed directory. Author: Eric.Sun
# ---------------------------------------------------------------------------

# Make sure prerequisite environment variables are set

CMD_LINE_ARGS="$*";

# Check JDK Environment
if [[ $JAVA_HOME == '' && $JRE_HOME == '' ]]; then
	echo "Neither the JAVA_HOME nor the JRE_HOME environment variable is defined (Oracle JDK 1.8.0_3xx)";
	echo "At least one of these environment variable is needed to run this program";
	exit 1;
fi

JAVA_SH="$JAVA_HOME/bin/java";
if [[ $JAVA_HOME != '' ]]; then
	if [[ ! -f $JAVA_SH ]]; then
		echo "The JAVA_HOME environment variable is NOT defined correctly as the \"$JAVA_HOME/bin/java\" is not found";
		exit 1;
	else
		JRE_HOME=$JAVA_HOME;
	fi
fi

JAVA_SH="$JRE_HOME/bin/java";
if [[ $JRE_HOME != '' && ! -f $JAVA_SH ]]; then
	echo "The JRE_HOME environment variable is NOT defined correctly as the \"$JRE_HOME/bin/java\" is not found";
	exit 1;	 	
fi

BASE_PATH=$(cd $(dirname "$0"); pwd);
PARENT_PATH=$(dirname "$BASE_PATH");

CLASSPATH=".";
for JAR_PATH in $(find "$PARENT_PATH/lib/" -type f -name '*.jar'|sort);
do
    CLASSPATH=$CLASSPATH":"$JAR_PATH;
done

CLASSPATH=$CLASSPATH":"$PARENT_PATH/conf/


# ####################################################################################
#        This shell snippets is used for setting JAVA OPTS: -Xms, -Xmx and GC
#                          Support on Linux/MacOSX
# ####################################################################################
VM_OPTS="-Xms4G -Xmx4G"

# Function to validate and set memory size
validate_and_set_memory() {
    local mem_value="$1"
    if [[ $mem_value =~ ^[1-9][0-9]*[KkMmGgTt]?$ ]]; then
        VM_OPTS="-Xms${mem_value} -Xmx${mem_value}"
        echo "You have successfully set the memory value: $mem_value"
    else
        echo "Error: The memory value format is incorrect. It should be in units of numbers plus K, M, G or T."
        exit 1
    fi
}

for (( i=1; i <= $#; i++ )); do
    arg="${!i}"
    # Check for --mem with a separate value
    if [[ $arg == "--mem" ]]; then
        if (( i >= $# )); then
            echo "Error: Memory value needs to be specified after --mem"
            exit 1
        fi
        ((i++))
        mem_size="${!i}"
        validate_and_set_memory "$mem_size"
        continue
    fi

    # Check for --mem=value
    if [[ $arg =~ ^--mem= ]]; then
        mem_size="${arg#*--mem=}"
        validate_and_set_memory "$mem_size"
        continue
    fi
done

GC_OPTS="-XX:+UseG1GC"

# ####################################################################################
#                               Set GC_OPTS by JAVA VERSIONRE
#                        Option: -XX:+UseG1GC used for JDK >1.8.0_300
#                  Option: -XX:+UseConcMarkSweepGC used for JDK <1.8.0_300
# ####################################################################################
JAVA_VERSION=$($JAVA_SH -version 2>&1 | sed '1!d' | sed -e 's/"//g' | awk '{print $3}');
if [[ "${JAVA_VERSION}" != '' ]]; then
    MAJOR_VERSION=$(echo "${JAVA_VERSION}" | awk -F'_' '{print $1}');
    # shellcheck disable=SC2077
    if [[ "${MAJOR_VERSION}" == '1.8.0' ]]; then
        MINOR_VERSION=$(echo "${JAVA_VERSION}" | awk -F'_' '{print $2}');
        if [[ ${MINOR_VERSION} -lt 300 ]]; then
            GC_OPTS="-XX:+UseConcMarkSweepGC"
        fi
    fi
else
    echo -e "The java -version is <UNKNOWN>. Please check java command is available";
fi

OS_NAME=$(uname);
# shellcheck disable=SC2077
if [[ "${OS_NAME}" == 'Linux' ]]; then

    if [[ $EXPERIMENTAL -eq 1 ]]; then
        # ####################################################################################
        #                        (Experimental)
        #                        Set VM_OPTS by System Memory
        #                       -Xms,-Xmx = min(48G, max(1GB, mem * 0.6))
        #
        #                        Set GC_THREAD_OPTS/CI_THREAD_OPTS by CPU Processors
        #                       -XX:CICompilerCount, -XX:ParallelGCThreads = max(8, CPU_THREADS)
        # ####################################################################################
        CPU_THREADS=$(cat /proc/cpuinfo | grep "processor" | wc -l);
        if [[ $CPU_THREADS -gt 8 ]]; then
            CPU_THREADS=8;
        fi
        GC_OPTS="$GC_OPTS -XX:CICompilerCount=$CPU_THREADS -XX:ParallelGCThreads=$CPU_THREADS";

        FREE_MEM=$(free mem | grep 'Mem' | awk '{print $4}');
        # shellcheck disable=SC2004
        ALLOC_MEM=$(($FREE_MEM * 6 / 10485760));
        # echo -e "Free Mem: ${FREE_MEM}\tAlloc Mem: ${ALLOC_MEM}GB"
        if [[ $ALLOC_MEM -lt 1 ]]; then
            echo -e "Error: Allocated memory is less than 1GB";
            exit 1;
        else
            if [[ $ALLOC_MEM -gt 48 ]]; then
                ALLOC_MEM=48;
            fi
            VM_OPTS="-Xms${ALLOC_MEM}G -Xmx${ALLOC_MEM}G";
        fi
        echo -e "JAVA_OPTS: $JAVA_VERSION $MAJOR_VERSION $MINOR_VERSION $GC_OPTS $VM_OPTS";
    fi
else
    echo -e "Warn: \"${OS_NAME}\" operating system doesn't support dynamic settings";
fi

JAVA_OPTS="$JAVA_OPTS -server $VM_OPTS -XX:MetaspaceSize=128M -XX:MaxMetaspaceSize=128M -Xss512K";
JAVA_OPTS="$JAVA_OPTS $GC_OPTS -Xnoclassgc -XX:MaxGCPauseMillis=50";
JAVA_OPTS="$JAVA_OPTS -XX:+HeapDumpOnOutOfMemoryError -Dsun.stdout.encoding=UTF-8 -Dsun.stderr.encoding=UTF-8";

# This variable decides the threshold to report a slow sql. Unit: milliseconds.
PROGRAM_OPTS="${PROGRAM_OPTS} -DsqlMonitor.slowSql.threshold=3000"

PROGRAM_OPTS="-Dpicocli.usage.width=180 -Dfs.page=1048576 -Dfile.split=SAFE -Ddry.run=false -Drebalance.import=true";
# This variable decides whether to enable sql monitor log.
PROGRAM_OPTS="${PROGRAM_OPTS} -DsqlMonitor.enabled=true"
PROGRAM_OPTS="${PROGRAM_OPTS} -Dtool.base.dir=$PARENT_PATH";
# PROGRAM_OPTS="${PROGRAM_OPTS} -Dobproxy.configurationFile=$PARENT_PATH/conf/secure.crt";
PROGRAM_OPTS="${PROGRAM_OPTS} -Dsession.configurationFile=$PARENT_PATH/conf/session.config.json";
PROGRAM_OPTS="${PROGRAM_OPTS} -Dsecurity.configurationFile=$PARENT_PATH/conf/security.properties";
PROGRAM_OPTS="${PROGRAM_OPTS} -Dlog4j.output=$PARENT_PATH/logs -Dlog4j2.formatMsgNoLookups=true -Dlog4j.configurationFile=file://$PARENT_PATH/conf/log4j2.xml";

JAVA_CMD="$JAVA_SH $JAVA_OPTS $PROGRAM_OPTS -classpath $CLASSPATH com.oceanbase.tools.loaddump.cmd.Obloader";

if [[ $DEBUG_MODE -eq 1 ]]; then
    PROGRAM_OPTS="${PROGRAM_OPTS} -Dlogback.configurationFile=$PARENT_PATH/conf/jdbc-trace.xml";
    echo "JAVA_CMD: $JAVA_CMD $CMD_LINE_ARGS";
fi
eval '$JAVA_CMD "$@"';