#!/bin/env bash
##Description: backup data

script_run_role="PRIMARY,STANDBY"
script_base_name="tidb_so_primary_dumpling"


function f_syntax
{
    [ ! -z "$1" ] && echo ">>[$(date "+%Y%m%d.%H%M%S")] $1"
    echo " "
    echo "bash ${ShellName}  [-primaryhostname <hostname>]"
    echo "-standbyhostname <hostname_standby> -backupdb <db_list>"
    echo " "
    echo " #Description:"
    echo " -primaryhostname ,the primary cluster manager host"
    echo " -standbyhostname ,the standby cluster manager host"
    echo " -backupdb ,the databases need to backup, eg: db1,db2,test"
    echo " "
    echo " #sample:"
    echo " #sh ${ShellName} -primaryhostname node1 -standbyhostname sa-172-16-4-81" 
    echo " "
    exit 22
}

function f_PrintLog
{
    _LogFlag=$(echo "$1"|tr "a-z" "A-Z")
    _LogMessage=$2
    [ $(echo "$1"|wc -L) -eq 4 ] && _LogFlag=$(echo "${_LogFlag}_")
    # echo "$(date "+%Y%m%d.%H%M%S"):[${_LogFlag}]:${UserName}@${HostName}:${2}";
    declare LogFile="${LogFile:-"/tmp/${ShellName}.log"}"
    touch "${LogFile}" 2>/dev/null
    if [ -w "${LogFile}" ]
    then
        echo "$(date "+%Y%m%d.%H%M%S"):[${_LogFlag}]:${UserName}@${HostName}:${2}"|tee -a "${LogFile}";
    else
        echo "$(date "+%Y%m%d.%H%M%S"):[${_LogFlag}]:${UserName}@${HostName}:${2}";
    fi

}

###############################################################################


function f_CheckDumplingCount
{
    f_PrintLog "Info" "Start to run f_CheckDumplingCount."
    MaxRunningCount=0
    ##Check ShellCount##
    for i in 1 2 3 4 5
    do
        ShellCount=$(ps -ef|grep "dumpling"|grep -vE "$$|cat|more|vi|view|grep|tail|tee"|awk 'END{print NR}')
        if [ ${ShellCount} -le ${MaxRunningCount:-0} ]
        then
            break
        fi

        ps -ef|grep "dumpling"|grep -vE "$$|cat|more|vi|view|grep|tail|tee"
        f_PrintLog "Warn" "dumpling is running, running count:${ShellCount}, greater then ${MaxRunningCount:-0}, continue ${i}";
        sleep 5
    done

    if [ ${ShellCount} -gt ${MaxRunningCount:-0} ]
    then
        ps -ef|grep "dumpling"
        f_PrintLog "Error" "Dumpling is current running, current pid is $$, exit!!!";
        exit 1
    fi
}

function f_backupsizecheck
{
    _clsname=$1

    f_PrintLog "Info" "Start to run f_backupsizecheck."
    
    pdNode=$(tiup cluster display ${_clsname}  2>/dev/null |awk  '{
        if($2=="pd" && $6~"Up"){printf "%s\n",$1;exit}
        }')
    f_PrintLog "Info" "Get cluster size pd-ctl ${pdNode}"
    pdRepls=$(pd-ctl --pd="http://${pdNode}" config show replication | awk -F: '{if($1~"max-replicas"){gsub(",","",$2);printf "%d",$2;exit}}')
    storeSize=$(pd-ctl --pd="http://${pdNode}" store | awk '{if($1~"used_size"){gsub(",","",$2);gsub("\"","",$2);printf "%s\t",$2}}')
    sizeMB=0
    for _size in ${storeSize}
    do
        _sizemb=$(echo ${_size}|awk '
            /.*KiB/{gsub("KiB","",$1);sz=$1/1000}
            /.*MiB/{gsub("MiB","",$1);sz=$1}
            /.*GiB/{gsub("GiB","",$1);sz=$1*1000}
            /.*TiB/{gsub("TiB","",$1);sz=$1*1000000}
            END{printf "%d\n",sz}
            ')
        sizeMB=$((sizeMB+_sizemb))
    done
    f_PrintLog "Info" "Cluster ${_clsName} size is ${sizeMB}MiB, max-replicas:${pdRepls}"
    sizeMB=$((sizeMB/pdRepls*3/2))
    
    df -h
    diskFree=$(df -P -m ${backupdir}|awk '!/Filesystem/{printf "%d",$4;exit}')
    if [ ${diskFree:-1} -gt ${sizeMB:-1} ]
    then
        f_PrintLog "Info" "backup dir ${backupdir} free space is ${diskFree}MB, greater then dbsize ${sizeMB}MB"
    else
        f_PrintLog "Error" "backup dir ${backupdir} free space is ${diskFree}MB, less then dbsize ${sizeMB}MB, quit!!!"
        exit 1
    fi
}


function f_rundumpling
{
    _ip=$1

    f_PrintLog "Info" "Start to run f_rundumpling."
    
    #dumpling config
    numProc=$(awk '/^processor[ |\t]*:/{c++}END{print c}' /proc/cpuinfo 2>/dev/null)
    if [ ${numProc} -ge 40 ]
    then
        thread=12
    elif [ ${numProc} -ge 20 ]
    then
        thread=6
    else
        thread=4
    fi

    enginetype='tidb_isolation_read_engines=tikv'
    _snapshot=$(date "+%Y-%m-%d %H:%M:%S")
    _backupdir=${backupdir}/${RunTs}
    _baklogfile=${backupdir}/logs/dumpling_${_ip}_${RunTs}.log
    _snaptso=$(mysql --login-path=tidblogin -NBe "select conv(concat(bin(unix_timestamp(now())*1000),'000000000000000001'),2,10)")

    if [ ! -d ${backupdir} ]
    then
        f_PrintLog "Error" "backup dir ${backupdir} not exists, exit!!!"
        exit 1
    fi

    mkdir -p ${_backupdir}
    mkdir -p ${backupdir}/logs

    [ -n "${backupdb}" ] && db_option="-B ${backupdb}" || db_option=""
    [ -n "${_snaptso}" ] && snap_option="--snapshot ${_snaptso}"
    conn_option="-h${_ip} -P${tidbPort} -u${user}"
    dir_option="-o ${_backupdir}"
    par_option="--filetype sql --params ${enginetype} -t ${thread} -r 200000 -F 256MiB"

    dumpling -V
    f_PrintLog "Info" "start to run dumpling backup, log file:${_logfile} "
    f_PrintLog "Info" "parameter: ${conn_option} ${dir_option} ${db_option} ${par_option} -p "

    echo "dumpling ${conn_option} ${dir_option} ${db_option} ${snap_option} ${par_option} -p 123 2>&1 >> ${_baklogfile} "
    sleep 3
    dumpling ${conn_option} ${dir_option} ${db_option} ${snap_option} ${par_option} -p${tidbPasswd:-123}  2>&1  >> ${_baklogfile}  &
    f_PrintLog "Info" "run tiup dumpling finished background, backup dir is ${_backupdir} "
    ps -ef|grep "dumpling"
    sleep 10
    
    dumplingCount=$(ps -ef|grep "dumpling"|grep -vE "grep|tail|tee" |wc -l)
    dumplingSucc=$(tail ${_baklogfile}|grep "dump data successfully"|wc -l)

    ck_sql="select user,count(1) from information_schema.cluster_processlist group by user"
    f_PrintLog "Info" "START TO RUN SQL:${ck_sql}, DBinfo ${_ip}"
    mysql ${conn_option} -p${tidbPasswd:-123} -vvv -e "${ck_sql}"

    if [ ${dumplingCount:-0} -ge 1 ]
    then
        f_PrintLog "Info" "Dumpling is running background, pls monitor it and check the log file ${_baklogfile}"
    elif [ ${dumplingSucc} -eq 1 ]
    then
        f_PrintLog "Info" "Dumpling already finished, pls check the log file ${_baklogfile}"
    else
        f_PrintLog "Error" "Dumpling was not start running, pls check the log file ${_baklogfile}"
        exit 1
    fi

}


###############################################################################
##Init##
export LANG=en_US
TidbHome=$(awk -F: -v un="tidb" '{if($1==un){print $6;exit}}' /etc/passwd 2>/dev/null)
NumProc=$(awk '/^processor[ |\t]*:/{c++}END{print c}' /proc/cpuinfo 2>/dev/null)
ShellName="$(echo $0|awk -F / '{print $NF}')";ShellOption="$@";
WorkDir="$(echo $0|sed s/${ShellName}//g)";[ -z "${WorkDir}" ] && WorkDir=${PWD};cd ${WorkDir};WorkDir=${PWD}
LogDir="${TidbHome}/switchover/logs";mkdir -p ${LogDir};
RunTs=$(date "+%Y%m%d.%H%M%S")
LogFile="${LogDir}/${script_base_name}_${ShellName}.${RunTs}.log";
Shellcksum=$(cksum ${WorkDir%/}/${ShellName} 2>/dev/null|awk '{printf "%d",$1}')
declare -i UserID=$(id -u);declare UserName=$(whoami);declare HostName=$(hostname);
###############################################################################
##TiDB Var##
locallogin="tidblogin"
adminusers="root,tidb,timon,repl"
checkpointschema="tidb_binlog"
backupdir="/data2/tidbbackup"
user="timon"
tidbsoconfig="${TidbHome}/switchover/cluster_switchover.config"
[ -f ${tidbsoconfig} ] && source ${tidbsoconfig}
###############################################################################
###############################################################################
##Get inopt
[ -z "${ShellOption}" -a -z "${primaryhostname}" -a -z "${standbyhostname}" ] && f_syntax;
# [ -n "${ShellOption}" ] && f_syntax;
# [ -z "${ShellOption}" -a -z "${primaryhostname}" -a -z "${standbyhostname}" ] && f_syntax;
for inopt in ${ShellOption}
do
    case $(echo $inopt|tr a-z A-Z) in
    -PRIMARYHOSTNAME|-HOSTNAME) CurOpt="-HOSTNAME_P";continue;;
    -STANDBYHOSTNAME) CurOpt="-HOSTNAME_S";continue;;
    -BACKUPDB) CurOpt="-BACKUPDB";continue;;
    -HELP|--HELP|-H) f_syntax;;
    -*) CurOpt="";continue;;
    esac
    case "${CurOpt}" in
    -HOSTNAME_P) declare primaryhostname="${inopt}";continue;;
    -HOSTNAME_S) declare standbyhostname="${inopt}";continue;;
    -BACKUPDB) declare backupdb="${inopt}";continue;;
    esac
done

f_PrintLog "Info" "Start to run Script ${ShellName}, the Shellcksum is ${Shellcksum}"
f_PrintLog "Info" "Script Options:${ShellOption}"


function f_readandcheckconfig
{

    f_PrintLog "Info" "Start to run f_readandcheckconfig."
    #
    [ -f ${tidbsoconfig} ] && source ${tidbsoconfig} 
    appusers="${PRIMARYAPPUSERS}"
    tidbPasswd=$(echo "${PASSWD}="|base64 -d)
    tidbIp="${PRIMARYIP}"
    tidbIp_s="${STANDBYIP}"
    tidbPort="${PRIMARYPORT}"
    clsName="${PRIMARYCLUSTERNAME}"
    clsName_s="${STANDBYCLUSTERNAME}"
    tidbDrainerId="${PRIMARYT2TDRAINER%,*}"
    backupdir="${BACKUPDIR:-/tidbbackup}"
    
    f_PrintLog "Info" "Get ${HostRole} cluster info finished. clsname:${clsName}, clsname_s:${clsName_s}, Ip:${tidbIp}, standbyIp:${tidbIp_s}, drainerId:${tidbDrainerId}"

    f_PrintLog "Info" "Check config hostname and cluster name."
    clsNamelocal=$(tiup cluster list 2>/dev/null|awk '{if($3~"v" && $4~"tiup"){printf "%s\n",$1;exit}}') 
    if [ -z "${clsNamelocal}" ]
    then
        f_PrintLog "Error" "Can not find valid cluster name using:tiup cluster list"
        exit 1
    else
        f_PrintLog "Info" "Find valid local cluster: ${clsNamelocal}"
        tiup cluster display ${clsNamelocal} 
    fi

    if [ "${HostRole}" = "PRIMARY" -a "${clsName}" != "${clsNamelocal}" ]
    then
        f_PrintLog "Error" "Check config clsname failed, PRIMARY CLUSTERNAME: ${clsName} != ${clsNamelocal}, exit!!!"
        exit 1
    elif [ "${HostRole}" = "PRIMARY" -a "${PRIMARYHOSTNAME}" != "${HostName}" ]
    then
        f_PrintLog "Error" "Check config hostname failed, PRIMARY HOSTNAME: ${PRIMARYHOSTNAME} != ${HostName}, exit!!!"
        exit 1
    elif [ "${HostRole}" = "STANDBY" -a "${clsName_s}" != "${clsNamelocal}" ]
    then
        f_PrintLog "Error" "Check config clsname failed, STANDBY CLUSTERNAME: ${clsName_s} != ${clsNamelocal}, exit!!!"
        exit 1
    elif [ "${HostRole}" = "STANDBY" -a "${STANDBYHOSTNAME}" != "${HostName}" ]
    then
        f_PrintLog "Error" "Check config hostname failed, STANDBY HOSTNAME: ${STANDBYHOSTNAME} != ${HostName}, exit!!!"
        exit 1
    fi
}


function f_dumplingmain
{
    f_PrintLog "Info" "Start to run f_dumplingmain."
    if [ -z "${backupdir}" -o ! -d "${backupdir}" ]
    then
        f_PrintLog "Error" "backupdir ${backupdir} not exists, exit!!!"
        exit 1
    fi

    f_CheckDumplingCount
    f_backupsizecheck "${clsName}"
    f_rundumpling "${tidbIp}"
}


###################
####    Main   ####
###################


function f_primary_dumpling_main
{
    f_PrintLog "Info" "Start to run Script ${ShellName} on ${HostName}, script_base_name ${script_base_name}."

    if [ -f ${tidbsoconfig} ] 
    then
        f_PrintLog "Info" "Start to buildin config variables, ${tidbsoconfig}."
        source ${tidbsoconfig}
        curdt=$(date +%Y%m%d)
        if [ -z $(echo ${PRIMARYRUNTIME} | grep ${curdt}) ]
        then
            f_PrintLog "Error" "Invalid config file, RUNTIME:${PRIMARYRUNTIME}, ${tidbsoconfig}."
            exit 1
        fi
    else
        f_PrintLog "Error" "Can not find valid config, ${tidbsoconfig}, exit"
        exit 1
    fi 

    #local var
    localProc=$(ps -ef | grep "tidb-server -P 4000"| grep -v grep)
    localPort=$(echo ${localProc}|awk -F"-P" '{print $2}'|awk '{printf "%d",$1}')
    localIp=$(echo ${localProc}|awk -F"--advertise-address=" '{print $2}'|awk '{printf "%s",$1}')
    tidbIpLocal="${localIp}"

    #check script var
    #check host role
    if [ "${primaryhostname}" != "${HostName}" -a "${standbyhostname}" != "${HostName}" ] 
    then
        f_PrintLog "Error" "InputHost are ${primaryhostname} and ${standbyhostname}, but now i am ${HostName}, exit"
        # exit 1
    fi
    
    if [ "${primaryhostname}" = "${HostName}" ] 
    then
        HostRole="PRIMARY"
    elif [ "${standbyhostname}" = "${HostName}" ]
    then
        HostRole="STANDBY"
    else
        HostRole="UNKNOWN"
    fi
    
    if [ "${PRIMARYHOSTNAME}" != "${HostName}" -a "${STANDBYHOSTNAME}" != "${HostName}" ]
    then
        f_PrintLog "Info" "Current hostname is ${HostName}, the script need to run on  ${PRIMARYHOSTNAME}, quit"
        exit 0
    fi


    #获取脚本执行需要的集群信息
    f_readandcheckconfig  
    f_PrintLog "Info" "Get ${HostRole} cluster info finished. clsname:${clsName}, clsname_s:${clsName_s}, Ip:${tidbIp}, standbyIp:${tidbIp_s}, drainerId:${tidbDrainerId}"
    f_PrintLog "Info" "Get ${HostRole} cluster info finished. clsname:${clsName}, backupdir:${backupdir}, Ip:${tidbIp}"
    
    if [ "${HostRole}" = "STANDBY" ]
    then
        f_PrintLog "Info" "Script ${script_base_name} need to run on PRIMARY node, but hostrole: ${HostRole}, quit."
        exit 0
    fi

    #执行主集群的复制暂停
    f_dumplingmain

    #执行dumpling
    f_PrintLog "Info" "Successful to run Script ${ShellName} on ${HostName}, script_base_name ${script_base_name}."
    exit 0

}

f_primary_dumpling_main 
# exit ${PIPESTATUS[0]} 


