如何安全的删除 xlog 文件
判定脚本
xlog_recycle_check.sh 点击查看代码
#!/bin/bash
usage()
{
echo "Usage: "
echo " $0 [OPTION] ... [XLOGFILES]"
echo
echo "Options:"
echo " -x xlog_segsize, xlog 文件段大小,单位 MB,默认 64 MB"
echo " -v, 打印调试信息"
echo
exit 0
}
debug_echo()
{
if [[ $verbose -eq 1 ]]; then
echo "$@"
fi
}
# 解析参数
while getopts "x:v" opt
do
case $opt in
x ) # 单位 MB ,默认 64 MB
xlog_segsize="$OPTARG"
;;
v )
verbose=1
;;
\? )
usage
;;
esac
done
shift $(($OPTIND-1))
# xlog 文件段
xlog_files=("$@")
[[ ${#xlog_files[@]} -eq 0 ]] && usage
# 设置默认值
verbose=${verbose:=0}
xlog_segsize="${xlog_segsize:=64}"
# 计算 xlog 分组进制 (4GB/xlog_segsize)
xlog_radix=$((0x100000000/($xlog_segsize*1024*1024)))
debug_echo "xlog radix: $xlog_radix"
# 遍历 xlog 文件段
for xlog_file in ${xlog_files[@]}
do
xlog_base="$(basename $xlog_file)"
if [[ ! $xlog_base =~ ^[0-9A-Z]{24}$ ]]; then
debug_echo "$xlog_file is NOT xlog file"
continue
fi
echo "xlog base: $xlog_base"
echo "xlog file: $xlog_file"
# 根据文件名计算当前文件的第一个 page 的LSN
xlog_timeline="0x${xlog_base:0:8}"
debug_echo "xlog timeline: $xlog_timeline"
xlog_group="0x${xlog_base:8:8}"
debug_echo "xlog group: $xlog_group"
xlog_index="0x${xlog_base:16:8}"
debug_echo "xlog index: $xlog_index"
debug_echo "xlog calc expr: ($xlog_group*$xlog_radix+$xlog_index)*$xlog_segsize*1024*1024"
xlog_first_page_lsn_calc=$((($xlog_group*$xlog_radix+$xlog_index)*$xlog_segsize*1024*1024))
echo "LSN calc: $xlog_first_page_lsn_calc"
printf "LSN calc hex: 0x%016x\n" $xlog_first_page_lsn_calc
# 根据文件第 8~16 字节计算当前文件段第一个 page 的十六进制 LSN
xlog_first_page_lsn_line=($(hexdump -s 8 -n 8 $xlog_file -C | head -n 1))
debug_echo "LSN line: ${xlog_first_page_lsn_line[@]}"
xlog_first_page_lsn_bytes=(${xlog_first_page_lsn_line[@]:1:8})
debug_echo "LSN bytes: ${xlog_first_page_lsn_bytes[@]}"
xlog_first_page_lsn_hex="0x"
for((i=7;i>=0;i--))
do
xlog_first_page_lsn_hex+="${xlog_first_page_lsn_bytes[$i]}"
done
echo "LSN read hex: $xlog_first_page_lsn_hex"
diff=$(($xlog_first_page_lsn_calc-$xlog_first_page_lsn_hex))
if [[ $diff -ne 0 ]]; then
echo "[RESULT] $xlog_base recycled"
else
echo "[RESULT] $xlog_base matched"
fi
done
使用效果
-
查看一批 xlog 文件段
sh ~/xlog_recycle_check.sh pg_xlog/* | grep RESULT
-
查看指定 xlog 文件段
sh ~/xlog_recycle_check.sh pg_xlog/00000001000000010000001B
-
打印调试信息
sh -v ~/xlog_recycle_check.sh pg_xlog/000000010000000100000032
判定原理
WAL文件的命名包括三部分,每部分都是用8个16进制(4个字节)的字符串表示。
以 WAL 日志文件段64MB为例
● 第一部分,表示时间线,即WAL日志所在的时间线。
● 每4GB大小的日志文件段为一组,则每组有4GB/64MB=64个文件段,即每组的日志文件段至多64个,16进制的范围表示 00~3F,即第三部分的取值范围为 00~3F。
● 当日志的大小(LSN)每超过4GB,则向第二部分进一。
以 00000001000000110000001E 文件段为例:
● 第一部分:00000001 表示日志段所在的时间线为 0x00000001 = 1。
● 第二部分:00000011 表示日志段所在的组号(或者说第N个4GB日志文件,从0开始计数)为 0x00000011 = 17,即第18个4GB文件范围内。
● 第三部分:0000001E 表示日志段所在组的段号(即第N组的第M个文件段,从0开始计数)为 0000001E = 30
总结,00000001000000110000001E 为 第“0x00000011 * 64 + 0x0000001E = 17*64+30 = 1118”个64MB的文件段。
注:这里为什么要乘以64?
那么,该日志文件段,所表示的LSN的起始位置为:
1118 * 64 * 1024 * 1024 = 75027709952 = 0x1178000000
根据XLogPageHeaderData 结构体的定义,每一个XLOG的Page都会有这个页的一些头部信息。
● 前2字节,表示魔数,0xD07E
● 接着的2字节,表示一些flag
● 接着的4字节,表示时间线
● 接着的8字节,表示这个Page的起始LSN
再看下,00000001000000110000001E 文件的第8~16个字节,表示的是这个日志文件的第一个页的位置。(看样子是小端模式)。
hexdump -C -n 16 00000001000000110000001E
00000000 7e d0 06 00 01 00 00 00 00 00 00 78 11 00 00 00 |~..........x....|
00000010
根据日志文件的首页信息,可以看出,00000001000000110000001E 文件名与其内容是匹配的。
也可以用python3获取
python3 -c "
f=open('00000001000000110000001E', 'rb')
f.seek(8)
print(hex(int.from_bytes(f.read(8), byteorder='little')))
f.close()
"
那么,当日志文件被checkpoint进程recycle之后,会将旧的日志文件,重命名成新的日志文件,以减少文件的生成次数。
重命名的文件,其文件名与其内容是不匹配的。如 000000010000001100000026
hexdump -C -n 16 000000010000001100000026
00000000 7e d0 06 00 01 00 00 00 00 00 00 74 11 00 00 00 |~..........t....|
00000010
按照上述的说法:
000000010000001100000026的第一个首页的起始位置应该是:
(0x00000011 * 64 + 0x00000026) * (64 * 1024 * 1024) = 75564580864 = 0x1198000000
也就是说,000000010000001100000026 文件的第8~16个字节应该是:00 00 00 98 11 00 00 00,而不是现在的 00 00 00 74 11 00 00 00。
现在的 00 00 00 74 11 00 00 00,其表示的是 0x1174000000 这个首页的LSN地址。
反推,
0x1174000000/(6410241024) = 1117,即是第1117个64MB的文件。
按照每64个64MB文件为一组,其
● 组号为:1117 / 64 = 17 = 0x11
● 组内的段号为:1117 % 64 = 29 = 0x1D
即,这个文件的首页内容所在的WAL日志文件段名应该是:00000001000000110000001D
即,000000010000001100000026 是由 00000001000000110000001D 重命名的来。
🎈 所以,如果想要删除 WAL 文件段以回收空间时,尽量应该删除哪些 recycled 的 WAL 文件。
本文来自博客园,作者:Zaclu,转载请注明原文链接:https://www.cnblogs.com/zaclu/p/15424855.html