#!/bin/bash 

VERSION="2.0.4"
DEVICE_NAME="dm-0"
[[ $DEVICE ]] || DEVICE="252:0"
[[ $INTERVAL ]] || INTERVAL=8
CGROUP_PREFIX_CENTOS7="/sys/fs/cgroup/blkio/machine.slice"
UUID_SUFFIX_CENTOS7=".scope"
CGROUP_PREFIX_NEW="/cgroup/blkio/machine"
UUID_SUFFIX_NEW=".libvirt-qemu"
BINLOG_PREFIX="/sys/module/binlogdev/holders/cachedev"
rand_dir=$(uuidgen)
TEMP_DIR="/tmp/autolimit/$rand_dir"
[[ -d $TEMP_DIR ]] || mkdir -p $TEMP_DIR
LOG="/var/log/autolimit.log"
[[ -d $LOG ]] || touch $LOG
DEVICE_PATH="/dev/"$DEVICE_NAME
FLAG_FILE="/tmp/autolimit/util_flags"
GUEST_WHITELIST="/root/autolimit/guest.txt"
util_limit_flag=0

trap 'cleanup_exit; exit' SIGHUP SIGINT SIGQUIT

cleanup_exit() {
    if [[ -d $TEMP_DIR ]]; then
        rm -rf $TEMP_DIR
    fi
}

cleanup() {
    if [[ -d $TEMP_DIR ]]; then
        rm -rf $TEMP_DIR/*
    fi
}

do_limit() {
    for cgroup_path in $CGROUP_PREFIX_CENTOS7/machine-qemu\\x2d[0-9a-z]*\\x2d[0-9a-z]*\\x2d[0-9a-z]*\\x2d[0-9a-z]*\\x2d[0-9a-z]*$UUID_SUFFIX_CENTOS7
    do
        if [[ -d $cgroup_path ]]; then
            echo "$DEVICE $1" > $cgroup_path/blkio.throttle.write_iops_device
            echo "`date`: echo \"$DEVICE $1\" > $cgroup_path/blkio.throttle.write_iops_device" >> $LOG
        fi
    done
    for cgroup_path in $CGROUP_PREFIX_NEW/[0-9a-z]*-[0-9a-z]*-[0-9a-z]*-[0-9a-z]*-[0-9a-z]*$UUID_SUFFIX_NEW
    do
        if [[ -d $cgroup_path ]]; then
            echo "$DEVICE $1" > $cgroup_path/blkio.throttle.write_iops_device
            echo "`date`: echo \"$DEVICE $1\" > $cgroup_path/blkio.throttle.write_iops_device" >> $LOG
        fi
    done
}

set_all_cachedev_readonly() {
    for path in $BINLOG_PREFIX/[0-9]*_[0-9]*
    do
        OLD_IFS="$IFS"
        IFS=$'\x0A'
        for device_info in `cat $path/cache_device`
        do
            local device_state=`echo $device_info |awk '{print $8}'` 
			if [[ $device_state == "normal" ]]; then
                local device_name=`echo $device_info |awk '{print $1}'` 
                echo "setro $device_name" > $path/cache_device
                echo "`date`:setro \"$device_name\" > $path/cache_device" >> $LOG
			fi
	    done
	    IFS=$OLD_IFS
    done
}

set_all_cachedev_normal() {
    return
}

relieve_write_limit() {
    for cgroup_path in $CGROUP_PREFIX_CENTOS7/machine-qemu\\x2d[0-9a-z]*\\x2d[0-9a-z]*\\x2d[0-9a-z]*\\x2d[0-9a-z]*\\x2d[0-9a-z]*$UUID_SUFFIX_CENTOS7
    do
        if [[ -d $cgroup_path ]]; then
            if [[ -e $cgroup_path/blkio.throttle.write_iops_device ]]; then
                local iops=0
                iops=`cat $cgroup_path/blkio.throttle.write_iops_device | awk '{print $2}'`
                if [[ "x$iops" != x ]]; then
                    local set_iops=`expr $iops + 300`
                    if [[ $set_iops -gt 30000 ]]; then
                        set_iops=0
                    fi
                    echo "$DEVICE $set_iops" > $cgroup_path/blkio.throttle.write_iops_device
                    echo "`date`: echo \"$DEVICE $set_iops\" > $cgroup_path/blkio.throttle.write_iops_device" >> $LOG
                fi
            fi
        fi
    done
    for cgroup_path in $CGROUP_PREFIX_NEW/*
    do
        if [[ -d $cgroup_path ]]; then
            if [[ -e $cgroup_path/blkio.throttle.write_iops_device ]]; then
                local iops=0
                iops=`cat $cgroup_path/blkio.throttle.write_iops_device | awk '{print $2}'`
                if [[ "x$iops" != x ]]; then
                    local set_iops=`expr $iops + 300`
                    if [[ $set_iops -gt 30000 ]]; then
                        set_iops=0
                    fi
                    echo "$DEVICE $set_iops" > $cgroup_path/blkio.throttle.write_iops_device
                    echo "`date`: echo \"$DEVICE $set_iops\" > $cgroup_path/blkio.throttle.write_iops_device" >> $LOG
                fi
            fi
        fi
    done
}

relieve_read_limit() {
    for cgroup_path in $CGROUP_PREFIX_CENTOS7/machine-qemu\\x2d[0-9a-z]*\\x2d[0-9a-z]*\\x2d[0-9a-z]*\\x2d[0-9a-z]*\\x2d[0-9a-z]*$UUID_SUFFIX_CENTOS7
    do
        if [[ -d $cgroup_path ]]; then
            if [[ -e $cgroup_path/blkio.throttle.read_iops_device ]]; then
                local iops=0
                iops=`cat $cgroup_path/blkio.throttle.read_iops_device | awk '{print $2}'`
                if [[ "x$iops" != x ]]; then
                    local set_iops=`expr $iops + 50`
                    if [[ $set_iops -gt 2800 ]]; then
                        set_iops=0
                    fi
                    echo "$DEVICE $set_iops" > $cgroup_path/blkio.throttle.read_iops_device
                    echo "`date`: echo \"$DEVICE $set_iops\" > $cgroup_path/blkio.throttle.read_iops_device" >> $LOG
                fi
            fi
        fi
    done
    for cgroup_path in $CGROUP_PREFIX_NEW/*
    do
        if [[ -d $cgroup_path ]]; then
            if [[ -e $cgroup_path/blkio.throttle.read_iops_device ]]; then
                local iops=0
                iops=`cat $cgroup_path/blkio.throttle.read_iops_device | awk '{print $2}'`
                if [[ "x$iops" != x ]]; then
                    local set_iops=`expr $iops + 50`
                    if [[ $set_iops -gt 2800 ]]; then
                        set_iops=0
                    fi
                    echo "$DEVICE $set_iops" > $cgroup_path/blkio.throttle.read_iops_device
                    echo "`date`: echo \"$DEVICE $set_iops\" > $cgroup_path/blkio.throttle.read_iops_device" >> $LOG
                fi
            fi
        fi
    done
}

do_extend_vm() {
    for cgroup_path in $CGROUP_PREFIX_CENTOS7/machine-qemu\\x2d[0-9a-z]*\\x2d[0-9a-z]*\\x2d[0-9a-z]*\\x2d[0-9a-z]*\\x2d[0-9a-z]*$UUID_SUFFIX_CENTOS7
    do
        if [[ -d $cgroup_path ]]; then
            local iops=0
            iops=`cat $cgroup_path/blkio.throttle.write_iops_device | awk '{print $2}'`
            if [[ "x$iops" = x ]]; then
                iops=0
            fi
            if [[ $iops -gt 0 ]]; then
                iops=`expr $iops \* $1 / 100`
                if [[ $iops -gt 100000 ]]; then
                    iops=0
                fi
                echo "$DEVICE $iops" > $cgroup_path/blkio.throttle.write_iops_device
                echo "`date`: echo \"$DEVICE $iops\" > $cgroup_path/blkio.throttle.write_iops_device" >> $LOG
            fi
        fi
    done
    for cgroup_path in $CGROUP_PREFIX_NEW/[0-9a-z]*-[0-9a-z]*-[0-9a-z]*-[0-9a-z]*-[0-9a-z]*$UUID_SUFFIX_NEW
    do
        if [[ -d $cgroup_path ]]; then
            local iops=0
            iops=`cat $cgroup_path/blkio.throttle.write_iops_device | awk '{print $2}'`
            if [[ "x$iops" = x ]]; then
                iops=0
            fi
            if [[ $iops -gt 0 ]]; then
                iops=`expr $iops \* $1 / 100`
                if [[ $iops -gt 100000 ]]; then
                    iops=0
                fi
                echo "$DEVICE $iops" > $cgroup_path/blkio.throttle.write_iops_device
                echo "`date`: echo \"$DEVICE $iops\" > $cgroup_path/blkio.throttle.write_iops_device" >> $LOG
            fi
        fi
    done
}

binlog_get_dirty() {
    dirty_blocks=0
    for stat_path in $BINLOG_PREFIX/[0-9]*_[0-9]*
    do
        if [[ -d $stat_path ]]; then
            OLD_IFS="$IFS"
            IFS=$'\x0A'
            for context in `cat $stat_path/stat`
            do
                echo $context | grep -q "memory_dirty_blocks:"
                if [ $? -eq 0 ]; then
                    dirty_blocks=`echo $context | awk '{print $2}'`
                    echo "dirty_blocks:$dirty_blocks"
                    break
                fi
            done
            IFS=$OLD_IFS
        fi
    done
}

store_vm_write() {
    local OLD_IFS=$IFS
    IFS=$'\n'
    for line in `virsh list | grep -v vnat | grep -v -E '^[-]' | grep -v Id`
    do
	uuid=`echo $line | awk '{print $2}'` 
	id=`echo $line | awk '{print $1}'`
	uuid_1=`echo $uuid | awk -F - '{print $1}'`
	uuid_2=`echo $uuid | awk -F - '{print $2}'`
	uuid_3=`echo $uuid | awk -F - '{print $3}'`
	uuid_4=`echo $uuid | awk -F - '{print $4}'`
	uuid_5=`echo $uuid | awk -F - '{print $5}'`
	if [[ -e $CGROUP_PREFIX_CENTOS7 ]]; then
            local uuid_path=$CGROUP_PREFIX_CENTOS7/machine-qemu\\x2d$id\\x2d$uuid_1\\x2d$uuid_2\\x2d$uuid_3\\x2d$uuid_4\\x2d$uuid_5$UUID_SUFFIX_CENTOS7
        else
            local uuid_path=$CGROUP_PREFIX_NEW/qemu-$id-$uuid$UUID_SUFFIX_NEW
        fi 
        local use_binlog=`cat $uuid_path/blkio.throttle.io_serviced | grep -E "\b$DEVICE\b"`
        if [[ ! $use_binlog ]]; then
            continue;
        fi

        w_io_start=$(cat $uuid_path/blkio.throttle.io_serviced | grep -E "\b$DEVICE\b" | grep -i write | awk '{print $3}')

        echo "${w_io_start}" > $TEMP_DIR/"write_"$uuid
    done
    IFS=$OLD_IFS
}

get_craze_write_vm() {
    cat /dev/null >$TEMP_DIR/write
    local OLD_IFS=$IFS
    IFS=$'\n'
    for line in `virsh list | grep -v vnat | grep -v -E '^[-]' | grep -v Id`
    do
	uuid=`echo $line | awk '{print $2}'` 
	id=`echo $line | awk '{print $1}'`
	uuid_1=`echo $uuid | awk -F - '{print $1}'`
	uuid_2=`echo $uuid | awk -F - '{print $2}'`
	uuid_3=`echo $uuid | awk -F - '{print $3}'`
	uuid_4=`echo $uuid | awk -F - '{print $4}'`
	uuid_5=`echo $uuid | awk -F - '{print $5}'`
	if [[ -e $CGROUP_PREFIX_CENTOS7 ]]; then
            local uuid_path=$CGROUP_PREFIX_CENTOS7/machine-qemu\\x2d$id\\x2d$uuid_1\\x2d$uuid_2\\x2d$uuid_3\\x2d$uuid_4\\x2d$uuid_5$UUID_SUFFIX_CENTOS7
        else
            local uuid_path=$CGROUP_PREFIX_NEW/qemu-$id-$uuid$UUID_SUFFIX_NEW
        fi
        local use_binlog=`cat $uuid_path/blkio.throttle.io_serviced | grep -E "\b$DEVICE\b"`
        if [[ ! $use_binlog ]]; then
            continue;
        fi

        w_io_start=$(cat $TEMP_DIR/"write_"$uuid | awk '{print $1}')
        w_io_end=$(cat $uuid_path/blkio.throttle.io_serviced | grep -E "\b$DEVICE\b" | grep -i write | awk '{print $3}')

        w_iops=$(echo "scale=0; ($w_io_end - $w_io_start) / $INTERVAL" | bc -l)
        echo "qemu-$id-$uuid    ${w_iops}" >>$TEMP_DIR/write
    done
    IFS=$OLD_IFS
    vm_write_uuid=`sort -k 2 -rn $TEMP_DIR/write | head -1 | awk '{print $1}'`
    vm_write_iops=`sort -k 2 -rn $TEMP_DIR/write | head -1 | awk '{print $2}'`
    echo "uuid:$vm_write_uuid iops:$vm_write_iops"
}

store_vm_read() {
    local OLD_IFS=$IFS
    IFS=$'\n'
    for line in `virsh list | grep -v vnat | grep -v -E '^[-]' | grep -v Id`
    do
	uuid=`echo $line | awk '{print $2}'` 
	id=`echo $line | awk '{print $1}'`
	uuid_1=`echo $uuid | awk -F - '{print $1}'`
	uuid_2=`echo $uuid | awk -F - '{print $2}'`
	uuid_3=`echo $uuid | awk -F - '{print $3}'`
	uuid_4=`echo $uuid | awk -F - '{print $4}'`
	uuid_5=`echo $uuid | awk -F - '{print $5}'`
	if [[ -e $CGROUP_PREFIX_CENTOS7 ]]; then
            local uuid_path=$CGROUP_PREFIX_CENTOS7/machine-qemu\\x2d$id\\x2d$uuid_1\\x2d$uuid_2\\x2d$uuid_3\\x2d$uuid_4\\x2d$uuid_5$UUID_SUFFIX_CENTOS7
        else
            local uuid_path=$CGROUP_PREFIX_NEW/qemu-$id-$uuid$UUID_SUFFIX_NEW
        fi
        local use_binlog=`cat $uuid_path/blkio.throttle.io_serviced | grep -E "\b$DEVICE\b"`
        if [[ ! $use_binlog ]]; then
            continue;
        fi

        r_io_start=$(cat $uuid_path/blkio.throttle.io_serviced | grep -E "\b$DEVICE\b" | grep -i read | awk '{print $3}')

        echo "${r_io_start}" > $TEMP_DIR/"read_"$uuid
    done
    IFS=$OLD_IFS
}

get_craze_read_vm() {
    cat /dev/null >$TEMP_DIR/read
    local OLD_IFS=$IFS
    IFS=$'\n'
    for uuid in `virsh list | grep -v vnat | grep -v -E '^[-]' | grep -v Id | awk '{print $2}'`
    do
	uuid=`echo $line | awk '{print $2}'` 
	id=`echo $line | awk '{print $1}'`
	uuid_1=`echo $uuid | awk -F - '{print $1}'`
	uuid_2=`echo $uuid | awk -F - '{print $2}'`
	uuid_3=`echo $uuid | awk -F - '{print $3}'`
	uuid_4=`echo $uuid | awk -F - '{print $4}'`
	uuid_5=`echo $uuid | awk -F - '{print $5}'`
	if [[ -e $CGROUP_PREFIX_CENTOS7 ]]; then
            local uuid_path=$CGROUP_PREFIX_CENTOS7/machine-qemu\\x2d$id\\x2d$uuid_1\\x2d$uuid_2\\x2d$uuid_3\\x2d$uuid_4\\x2d$uuid_5$UUID_SUFFIX_CENTOS7
        else
            local uuid_path=$CGROUP_PREFIX_NEW/qemu-$id-$uuid$UUID_SUFFIX_NEW
        fi
        local use_binlog=`cat $uuid_path/blkio.throttle.io_serviced | grep -E "\b$DEVICE\b"`
        if [[ ! $use_binlog ]]; then
            continue;
        fi

        r_io_start=$(cat $TEMP_DIR/"read_"$uuid | awk '{print $1}')
        r_io_end=$(cat $uuid_path/blkio.throttle.io_serviced | grep -E "\b$DEVICE\b" | grep -i read | awk '{print $3}')

        r_iops=$(echo "scale=0; ($r_io_end - $r_io_start) / $INTERVAL" | bc -l)
        echo "qemu-$id-$uuid    ${r_iops}" >>$TEMP_DIR/read
    done
    IFS=$OLD_IFS
    vm_read_uuid=`sort -k 2 -rn $TEMP_DIR/read | head -1 | awk '{print $1}'`
    vm_read_iops=`sort -k 2 -rn $TEMP_DIR/read | head -1 | awk '{print $2}'`
}

do_limit_vm() {
    binlog_get_dirty
    pre_dirty_blocks=$dirty_blocks
    store_vm_write

    sleep $INTERVAL

    binlog_get_dirty
    get_craze_write_vm

# 脏数据在不断上涨
        local min_iops=`expr 6144 \* $1 / 100`
        if [[ -e $GUEST_WHITELIST && $vm_write_uuid ]]; then
            local guest_min_write_iops=`cat $GUEST_WHITELIST | grep $vm_write_uuid | awk '{print $3}'`
            if [[ $guest_min_write_iops -gt $min_iops ]]; then
                min_iops=$guest_min_write_iops
                echo "`date`: do_limit_vm guest:$vm_write_uuid, min:$guest_min_write_iops" >> $LOG
            fi
        fi
        if [[ $vm_write_iops -gt 0 ]]; then
            vm_write_iops=`expr $vm_write_iops + 1`
            iops=`expr $vm_write_iops \* $1 / 100`
            if [[ $iops -lt $min_iops ]]; then
                iops=$min_iops
            fi
	    if [[ -e $CGROUP_PREFIX_OLD/$vm_write_uuid$UUID_SUFFIX_OLD ]]; then
                local uuid_path=$CGROUP_PREFIX_OLD/$vm_write_uuid$UUID_SUFFIX_OLD
            else
                local uuid_path=$CGROUP_PREFIX_NEW/$vm_write_uuid$UUID_SUFFIX_NEW
            fi
            echo "$DEVICE $iops" > $uuid_path/blkio.throttle.write_iops_device
            echo "`date`: echo \"$DEVICE $iops\" > $uuid_path/blkio.throttle.write_iops_device" >> $LOG
        fi
}

extend_io_limit() {
    echo "$1" > $BINLOG_PREFIX/iolimit_for_clean
    echo "`date`: echo \"$1\" > $BINLOG_PREFIX/iolimit_for_clean" >> $LOG
}

binlog_get_stat() {
    local valid_version=0
    local next_free_version=0
    for stat_path in $BINLOG_PREFIX/[0-9]*_[0-9]*
    do
        if [[ -d $stat_path ]]; then
            local OLD_IFS="$IFS"
            IFS=$'\x0A'
            for context in `cat $stat_path/stat`
            do
                echo $context | grep -q "valid_version:"
                if [ $? -eq 0 ]; then
                    valid_version=`echo $context | awk '{print $2}'`
                    continue
                fi

                echo $context | grep -q "next_free_version:"
                if [ $? -eq 0 ]; then
                    next_free_version=`echo $context | awk '{print $2}'`
                fi
            done
            IFS=$OLD_IFS
        fi
    done
    used_version=`expr $next_free_version - $valid_version`
    used_version=`expr $used_version \* 2`
    echo "used_version:$used_version"
}

extend_clean_count() {
    for path in $BINLOG_PREFIX/[0-9]*_[0-9]*
    do
        local clean_count=`cat $path/clean_count | grep local | awk '{print $2}' | sed -e "s/,//"`
        if [[ $clean_count -lt $1 ]]; then
            echo "local $1" > $path/clean_count
            echo "`date`: echo $1 > $path/clean_count" >> $LOG
        fi
    done
}

relieve_clean_count() {
    for path in $BINLOG_PREFIX/[0-9]*_[0-9]*
    do
        local clean_count=`cat $path/clean_count | grep local | awk '{print $2}' | sed -e "s/,//"`
        if [[ $clean_count -ne $1 ]]; then
            echo "local $1" > $path/clean_count
            echo "`date`: echo $1 > $path/clean_count" >> $LOG
        fi
    done
}

binlog_more_than_90_percent() {
    local iolimit=`cat $BINLOG_PREFIX/iolimit_for_clean`
    if [[ $iolimit -ne 204800 ]]; then
# 当binlog使用量为2.4T，进入高危模式
        extend_io_limit 204800
        do_limit 64
        set_all_cachedev_readonly
    fi
}

binlog_more_than_80_percent() {
    local iolimit=`cat $BINLOG_PREFIX/iolimit_for_clean`
    if [[ $iolimit -gt 102400 ]]; then
# 当binlog使用量恢复到2.3T，解除高危模式
        extend_io_limit 102400
        do_limit 512
    else
# 当binlog使用量为2.3T，限制所有vm的iops，设置全局IOPS为2048，同时加大clean_count到6144
        extend_io_limit 102400
        do_limit 512
        extend_clean_count 6144
    fi
}

binlog_more_than_60_percent() {
    local iolimit=`cat $BINLOG_PREFIX/iolimit_for_clean`
    if [[ $iolimit -ne 51200 ]]; then
# 当binlog使用量为2T，限制所有vm的iops, 同时加大clean_count到4096
        extend_io_limit 51200
        do_limit 3072
        extend_clean_count 4096
    fi
}

binlog_more_than_40_percent() {
    local iolimit=`cat $BINLOG_PREFIX/iolimit_for_clean`
    if [[ $iolimit -gt 20480 ]]; then
# 当binlog使用量恢复到1.5T，增加所有vm的iops限制量，解除全局限制
        do_extend_vm 200
    else
# 当binlog使用量超过1.5T，限制最高的iops的vm至50%
        do_limit_vm 50
        extend_clean_count 2048
    fi
            
    if [[ $iolimit -ne 20480 ]]; then
        extend_io_limit 20480
    fi
}

binlog_more_than_30_percent() {
    local iolimit=`cat $BINLOG_PREFIX/iolimit_for_clean`
    if [[ $iolimit -gt 10240 ]]; then
# 当binlog使用量恢复到1T，增加所有vm的iops限制量
        do_extend_vm 200
        relieve_clean_count 1536
    else
# 当binlog使用量超过1T，限制最高的iops的vm至80%
        do_limit_vm 80
        extend_clean_count 1536
    fi
    if [[ $iolimit -ne 10240 ]]; then
        extend_io_limit 10240
    fi
}

binlog_less_than_30_percent() {
    local iolimit=`cat $BINLOG_PREFIX/iolimit_for_clean`
    if [[ $iolimit -gt 4096 ]]; then
# 当binlog使用量小于1T，解除所有vm的iops限制
        relieve_write_limit
    fi
    if [[ $iolimit -ne 4096 ]]; then
        extend_io_limit 4096
    fi
    relieve_clean_count 1024
}

dirty_version_threshold() {
# calculate the used version
    binlog_get_stat

    if [[ $used_version -gt 600000000 ]]; then
        binlog_more_than_90_percent
    elif [[ $used_version -gt 500000000 ]]; then 
        binlog_more_than_80_percent
    elif [[ $used_version -gt 400000000 ]]; then
        binlog_more_than_60_percent
    elif [[ $used_version -gt 300000000 ]]; then
        binlog_more_than_40_percent
    elif [[ $used_version -gt 200000000 ]]; then
        binlog_more_than_30_percent
    else
        binlog_less_than_30_percent
    fi
}

dirty_blocks_threshold() {
# calculate the used version
    for path in $BINLOG_PREFIX/[0-9]*_[0-9]*
    do
        OLD_IFS="$IFS"
        IFS=$'\x0A'
        for device_info in `cat $path/cache_device`
        do
            local device_state=`echo $device_info |awk '{print $8}'` 
			if [[ $device_state == "readonly" ]]; then
				continue;
			fi
            local device_name=`echo $device_info |awk '{print $1}'` 
            local device_total_blocks=`echo $device_info |awk '{print $4}'` 
            local device_valid_blocks=`echo $device_info |awk '{print $5}'` 
            local device_next_free_blocks=`echo $device_info |awk '{print $6}'` 
            local device_thres_blocks=`expr $device_total_blocks \* 80 / 100` 
            if [[ $device_valid_blocks -lt $device_next_free_blocks ]]; then
				used_blocks=`expr $device_next_free_blocks - $device_valid_blocks`
				if [[ $used_blocks -gt $device_thres_blocks ]]; then
                    echo "setro $device_name" > $path/cache_device
                    echo "`date`:setro \" $device_name\" > $path/cache_device" >> $LOG
                fi
            fi
            if [[ $device_valid_blocks -gt $device_next_free_blocks ]]; then
				used_blocks=`expr $device_total_blocks - $device_valid_blocks`
				used_blocks=`expr $used_blocks + $device_next_free_blocks`
				if [[ $used_blocks -gt $device_thres_blocks ]]; then
                    echo "setro $device_name" > $path/cache_device
                    echo "`date`:setro \" $device_name\" > $path/cache_device" >> $LOG
                fi
            fi
	    done
	    IFS=$OLD_IFS
    done
}

do_utils_limit() {
    get_craze_write_vm
    get_craze_read_vm

    local min_read_iops=$2
    if [[ -e $GUEST_WHITELIST && $vm_read_uuid ]]; then
        local guest_min_read_iops=`cat $GUEST_WHITELIST | grep $vm_read_uuid | awk '{print $2}'`
        if [[ $guest_min_read_iops -gt $min_read_iops ]]; then
            min_read_iops=$guest_min_read_iops
            echo "`date`: do_utils_limit guest:$vm_read_uuid, use min read:$guest_min_read_iops" >> $LOG
        fi
    fi
    if [[ $vm_read_iops -gt $min_read_iops ]]; then
        vm_read_iops=`expr $vm_read_iops + 1`
        iops=`expr $vm_read_iops \* 90 / 100`
        if [[ $iops -lt $min_read_iops ]]; then
            iops=$min_read_iops
        fi
        if [[ -e $CGROUP_PREFIX_OLD/$vm_read_uuid$UUID_SUFFIX_OLD ]]; then
            local uuid_path=$CGROUP_PREFIX_OLD/$vm_read_uuid$UUID_SUFFIX_OLD
        else
            local uuid_path=$CGROUP_PREFIX_NEW/$vm_read_uuid$UUID_SUFFIX_NEW
        fi
        echo "$DEVICE $iops" > $uuid_path/blkio.throttle.read_iops_device
        echo "`date`: echo \"$DEVICE $iops\" > $uuid_path/blkio.throttle.read_iops_device" >> $LOG
    fi
    local min_write_iops=$1
    if [[ -e $GUEST_WHITELIST && $vm_write_uuid ]]; then
        local guest_min_write_iops=`cat $GUEST_WHITELIST | grep $vm_write_uuid | awk '{print $3}'`
        if [[ $guest_min_write_iops -gt $min_write_iops ]]; then
            min_write_iops=$guest_min_write_iops
            echo "`date`: do_utils_limit guest:$vm_write_uuid, use min write:$guest_min_write_iops" >> $LOG
        fi
    fi
    if [[ $vm_write_iops -gt $min_write_iops ]]; then
        vm_write_iops=`expr $vm_write_iops + 1`
        iops=`expr $vm_write_iops \* 90 / 100`
        if [[ $iops -lt $min_write_iops ]]; then
            iops=$min_write_iops
        fi
        if [[ -e $CGROUP_PREFIX_OLD/$vm_write_uuid$UUID_SUFFIX_OLD ]]; then
            local uuid_path=$CGROUP_PREFIX_OLD/$vm_write_uuid$UUID_SUFFIX_OLD
        else
            local uuid_path=$CGROUP_PREFIX_NEW/$vm_write_uuid$UUID_SUFFIX_NEW
        fi
        echo "$DEVICE $iops" > $uuid_path/blkio.throttle.write_iops_device
        echo "`date`: echo \"$DEVICE $iops\" > $uuid_path/blkio.throttle.write_iops_device" >> $LOG
    fi
}

utils_more_than_99() {
    util_limit_flag=1
    do_utils_limit 6144 1500
}

utils_more_than_95() {
    util_limit_flag=1
    do_utils_limit 8192 1500
}

utils_less_than_95() {
    if [[ $util_limit_flag != 1 ]]; then
        relieve_read_limit
        if [[ $used_blocks -lt 1138000000 ]]; then          # 1T
            relieve_write_limit
        fi
    fi
}

util_threshold() {
    local total_percet=1
    local nr_iostat=0
    store_vm_write
    store_vm_read
    iostat -mx $DEVICE_PATH 2 4 > $TEMP_DIR/iostat
    for p in `cat $TEMP_DIR/iostat | grep $DEVICE_NAME | awk 'NR>1 {print $12}'`
    do
        total_percet=$(echo "scale=0; $total_percet + $p" | bc -l)
        nr_iostat=`expr $nr_iostat + 1`
    done

    local percent=$(echo "scale=0; $total_percet / $nr_iostat" | bc -l)
    if [[ $percent -ge 99 ]]; then
        utils_more_than_99
    elif [[ $percent -ge 95 ]]; then
        utils_more_than_95
    else
        utils_less_than_95
    fi
    cleanup
}

whitelist_check_valid() {
    for whitelist_path in $BINLOG_PREFIX/[0-9]*_[0-9]*
    do
        for whitelist_pid in `cat $whitelist_path/whitelist_pid | grep pid: | awk '{print $2}'`
        do
            local pid=`ps -eL | awk '{print $2}' | grep $whitelist_pid`
            if [[ ! $pid ]]; then
                echo "del $whitelist_pid" > $whitelist_path/whitelist_pid
                echo "`date`: echo \"del $whitelist_pid\" > $whitelist_path/whitelist_pid" >> $LOG
            fi
        done
    done
}

whitelist_add_by_name() {
    local pid=`ps aux | grep $1 | grep -v grep | head -1 | awk '{print $2}'`

    for whitelist_path in $BINLOG_PREFIX/[0-9]*_[0-9]*
    do
        if [[ $pid ]]; then
            local in_whitelist=`cat $whitelist_path/whitelist_pid | grep $pid`
            if [[ ! $in_whitelist ]]; then
                echo "add $pid" > $whitelist_path/whitelist_pid
                echo "`date`: echo \"add $pid\" > $whitelist_path/whitelist_pid" >> $LOG
            fi
        fi
    done
}

do_whitelist() {
    whitelist_add_by_name RSCServer
    whitelist_check_valid
}


main() {
    if [[ ! -d $BINLOG_PREFIX ]]; then
        echo "Cannot find binlog path"
        cleanup_exit
        return
    fi

    do_whitelist
    dirty_version_threshold
    dirty_blocks_threshold
    cleanup
    for i in $(seq 3)
    do
        util_threshold
    done
    cleanup_exit
}

main
