#!/bin/env bash
##Description: run syncdiff
script_run_role="PRIMARY,STANDBY"
script_base_name="3_tidb_fb_standby_syncdiff"

function f_syntax
{
    [ ! -z "$1" ] && echo ">>[$(date "+%Y%m%d.%H%M%S")] $1"
    echo " "
    echo "bash ${ShellName}  [-primaryhostname <hostname>]"
    echo "-standbyhostname <hostname_standby> -syncdifftabs <tab_list>"
    echo " "
    echo " #Description:"
    echo " -primaryhostname ,the primary cluster manager host"
    echo " -standbyhostname ,the standby cluster manager host"
    echo " -syncdifftabs ,the tables need to backup, eg: db1.t*,db2.t2,test.*"
    echo " "
    echo " #sample:"
    echo " #sh ${ShellName} -primaryhostname node1 -standbyhostname sa-172-16-4-81 -syncdifftabs db1.t*,db2.t2,test.*" 
    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}";
}

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

function f_gettsmap
{
    f_PrintLog "Info" "Start to run f_gettsmap."

    #获取checkpoint表中的tsmap信息
    f_PrintLog "Info" "Start to run f_tsmap_stable."
    #tsmap
    ck_sql="select checkPoint from tidb_binlog.checkpoint order by clusterID desc limit 1"
    f_PrintLog "Info" "START TO RUN SQL:${ck_sql}, DBinfo tidblogin"
    exec_result=$(mysql --login-path=tidblogin -NBe "${ck_sql}")
    tsmap_tso=$(echo $exec_result  | python -m json.tool | awk '{if($0~"ry-ts"){printf "%s",$2}}')
    echo $exec_result  | python -m json.tool

    if [ -z "${tsmap_tso}" ]
    then
        f_PrintLog "Warn" "Binlog tsmap get failed!!!"
        exit 1
    else
        f_PrintLog "Info" "Binlog tsmap is ${tsmap_tso}!"
    fi
}


function f_generateconfig
{
    f_PrintLog "Info" "Start to run f_generateconfig."
    echo "${PRIMARYIP}:${PRIMARYPORT}:timon:${tidbPasswd:-123}"  "${tidbIp}:${localPort}:timon:${tidbPasswd:-123}" "${base_dir}" "${file_suffix}" "${syncdifftabs}" "${tsmap_tso}" "${thread}" 

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

python -c "
import sys,time

args = sys.argv
primary_info = args[1]
standby_info = args[2]
filedir = args[3]
file_suffix = args[4]
check_tabs = args[5]
tsmap = args[6]
thread_count = args[7]

P_ip = primary_info.split(':')[0]
P_port = primary_info.split(':')[1]
P_user = primary_info.split(':')[2]
P_pswd = primary_info.split(':')[3]

S_ip = standby_info.split(':')[0]
S_port = standby_info.split(':')[1]
S_user = standby_info.split(':')[2]
S_pswd = standby_info.split(':')[3]

P_tso = tsmap.split(',')[0]
S_tso = tsmap.split(',')[1]

tabs_lst = check_tabs.split(',')
tabs2_lst = []
for tab in tabs_lst:
    if '.' not in tab:
        tab = tab + '.*'
    tabs2_lst.append('\"%s\"' %(tab) )
checktabs_str = ','.join(tabs2_lst)

config_text = '''
# Sync Diff Configuration.
######################### Global config #########################
check-thread-count = %s
#split-thread-count = 64
export-fix-sql = true
check-struct-only = false

######################### Tables config #########################
[data-sources]
[data-sources.tidb_primary] 
    host = '%s'
    port = %s
    user = 'timon'
    password = '%s'
    snapshot = '%s'

[data-sources.tidb_slave]
    host = '%s'
    port = %s
    user = 'timon'
    password = '%s'
    snapshot = '%s'

[task]
    source-instances = ['tidb_primary']
    target-instance = 'tidb_slave'
    target-check-tables = [%s]
    output-dir = '%s/syncdiff_output_%s'
''' % (thread_count, P_ip, P_port, P_pswd, P_tso,  S_ip, S_port, S_pswd, S_tso, checktabs_str, filedir, file_suffix)

config_file='%s/syncdiff_%s.toml' %(filedir, file_suffix)

with open(config_file, mode='w') as f:
     f.write(config_text)
" "${PRIMARYIP}:${PRIMARYPORT}:timon:${tidbPasswd:-123}"  "${tidbIp}:${localPort}:timon:${tidbPasswd:-123}" "${base_dir}" "${file_suffix}" "${syncdifftabs}" "${tsmap_tso}" "${thread}" 
    
    f_PrintLog "Info" "run sync diff f_generateconfig finished, pls check ${syncdiff_config}"
    ls -l ${syncdiff_config:-1}
    cat ${syncdiff_config:-1}
}

function f_runsyncdiff
{
    f_PrintLog "Info" "Start to run f_runsyncdiff."
    configfile=$1

    f_PrintLog "Info" "Start to run syncdiff. sync_diff_inspector --config ${configfile}"
    sync_diff_inspector --config ${configfile}
    local _rt_code=$?
    local _fail=$(grep -i "check failed" ${output_dir}/sync_diff.log |wc -l)
    local _fini=$(grep -i "check data finished" ${output_dir}/sync_diff.log |wc -l)

    [ -f "${output_dir}/summary.txt" ] && tail -20 ${output_dir}/summary.txt
    
    if [ ${_rt_code} -eq 0 -a ${_fail} -eq 0 -a ${_fini} -ge 1 ]
    then
        f_PrintLog "Info" "f_runsyncdiff finish, return code:${_rt_code} fail:${_fail} finish:${_fini}"
        f_PrintLog "Info" "pls check summary log at ${output_dir}/summary.txt !"    
    else
        f_PrintLog "Warn" "f_runsyncdiff failed, return code:${_rt_code} fail:${_fail} finish:${_fini}"
        f_PrintLog "Error" "pls check summary and syncidff log at ${output_dir} !"    
        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}/scripts/flashback/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=""
adminusers=""
checkpointschema=""
backupdir=""
user=""
tidbPasswd=""
tidbfbconfig="${TidbHome}/scripts/flashback/cluster_flashback_config.cnf"
[ -f ${tidbfbconfig} ] && source ${tidbfbconfig}
###############################################################################
###############################################################################
##Get inopt
# [ -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) CurOpt="-HOSTNAME_P";continue;;
    -STANDBYHOSTNAME) CurOpt="-HOSTNAME_S";continue;;
    -SYNCDIFFTABS) CurOpt="-SYNCDIFFTABS";continue;;
    -HELP|--HELP|-H) f_syntax;;
    -*) CurOpt="";continue;;
    esac
    case "${CurOpt}" in
    -HOSTNAME_P) declare primaryhostname="${inopt}";continue;;
    -HOSTNAME_S) declare standbyhostname="${inopt}";continue;;
    -SYNCDIFFTABS) declare syncdifftabs="${inopt}";continue;;
    esac
done

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


function f_readandcheckconfig
{

    f_PrintLog "Info" "Start to run f_readandcheckconfig."
    #
    # [ -f ${tidbfbconfig} ] && source ${tidbfbconfig} 

    f_PrintLog "Info" "Get PRIMARY cluster info finished. clsname:${PRIMARYCLUSTERNAME}, Ip:${PRIMARYIP}, Port:${PRIMARYPORT}, standbyIp:${STANDBYIP}"

    f_PrintLog "Info" "Check config cluster name and ip."
    if [ -z "${clsName}" ]
    then
        f_PrintLog "Error" "Can not find valid cluster name using:tiup cluster list"
        exit 1
    elif [ -z $(echo "${clsName}"|grep "${PRIMARYCLUSTERNAME}") ]
    then
        f_PrintLog "Error" "Can not find matched cluster name, ${PRIMARYCLUSTERNAME}:${clsName}"
        exit 1
    else
        f_PrintLog "Info" "Find valid local cluster: ${clsName}"
        tiup cluster display ${clsName} 
    fi

    if [ "${tidbIp}" != "${STANDBYIP}" ]
    then
        f_PrintLog "Error" "Can not find matched standby ip, ${tidbIp}:${STANDBYIP}"
        exit 1
    else
        f_PrintLog "Info" "Local ip ${tidbIp} matched flashback config. "
    fi
    
}


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

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

    #local var
    clsNamelocal=$(tiup cluster list 2>/dev/null|awk '{if($3~"v" && $4~"tiup"){printf "%s\n",$1;exit}}') 
    localProc=$(ps -ef | grep "tidb-server -P 4"| grep -v grep)
    localPort=$(echo ${localProc}|awk -F"-P" '{print $2;exit}'|awk '{printf "%d",$1}')
    localIp=$(echo ${localProc}|awk -F"--advertise-address=" '{print $2;exit}'|awk '{printf "%s",$1}')
    tidbIp="${localIp}"
    clsName="${clsNamelocal}"
    f_PrintLog "Info" "Get local cluster info finished. clsname:${clsNamelocal}, Ip:${tidbIp}, Port:${localPort}"

    #check config var
    f_readandcheckconfig
    f_PrintLog "Info" "Get PRIMARY cluster info finished. clsname:${PRIMARYCLUSTERNAME}, Ip:${PRIMARYIP}, Port:${PRIMARYPORT}, standbyIp:${STANDBYIP}"


    file_suffix=${RunTs}
    syncdiff_config="${backupdir}/flashback/syncdiff/syncdiff_${file_suffix}.toml"
    output_dir="${backupdir}/flashback/syncdiff/syncdiff_output_${file_suffix}"
    base_dir="${backupdir}/flashback/syncdiff"
    mkdir -p "${base_dir}"
    
    #获取脚本执行需要的tsmap信息
    f_gettsmap
    f_PrintLog "Info" "Get checkpoint tsmap:${tsmap_tso}"

    if [ -z "${syncdifftabs}" ]
    then
        _execsql="select group_concat(distinct table_schema SEPARATOR ',') from  information_schema.tables where table_schema not in ('PERFORMANCE_SCHEMA','METRICS_SCHEMA','INFORMATION_SCHEMA','mysql','tidb_binlog')"
        f_PrintLog "Info" "START TO RUN SQL:${_execsql}, DBinfo ${tidbIp}"
        syncdifftabs=$(mysql --login-path=tidblogin -NBe "${_execsql}")
        f_PrintLog "Info" "run syncdiff with SyncTabs:${syncdifftabs}"
    fi

    f_PrintLog "Info" "Start to run syncdiff with SyncTabs:${syncdifftabs}"
    f_generateconfig 
    f_runsyncdiff "${syncdiff_config}"  
    
    f_PrintLog "Succ" "Run function f_standby_syncdiff_main finish!"
    f_PrintLog "Info" "Successful to run Script ${ShellName} on ${HostName}, script_base_name ${script_base_name}."
    exit 0
}

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


f_standby_syncdiff_main | tee -a ${LogFile}
exit ${PIPESTATUS[0]} 
