用 meta 索引离线校验,我把 2 万条记录的等待压到 1 分钟
meta 仓库里有一份索引文件,记录了 2.1 万条记录的路径、大小和修改时间戳,每行一条。本地是 macOS + zsh,索引文件 18MB 左右。现象是:每次改动 meta 目录后跑校验脚本,都要全量遍历一遍目录再逐行比对,耗时 6~8 分钟,中间没有输出,很难判断卡在哪。最烦的是磁盘上有几个挂载点偶尔掉线,脚本会卡在 stat 上不返回。
我的做法是把「遍历」和「比对」拆开,遍历只负责产出快照,比对交给 sort + comm。先按固定格式生成当前快照:
find meta -type f -printf '%p\t%s\t%T@\n' \
| sort -t$'\t' -k1,1 > /tmp/meta.now
索引文件本身也是同样三列,先裁剪掉注释行和空行,再导出成同一格式:
grep -v '^#' meta.index | grep -v '^$' \
| awk -F'\t' '{print $1"\t"$2"\t"$3}' \
| sort -t$'\t' -k1,1 > /tmp/meta.ref
然后只比较路径列,先拿到增删名单,再对交集部分比大小和时间:
comm -3 <(cut -f1 /tmp/meta.ref) <(cut -f1 /tmp/meta.now)
join -t$'\t' /tmp/meta.ref /tmp/meta.now \
| awk -F'\t' '$2!=$4 || $3!=$5'
find 那一步加了 -xdev,避免跨挂载点。掉线挂载点的问题没根治,只是把超时从「无限等」变成「跳过并记一条 warn」,用 timeout 5 stat 包了一层,代价是偶尔误报。
这么做的原因是:原来每读一行索引就 stat 一次磁盘,2.1 万次随机 stat 在机械盘上就是主要开销;现在 find 顺序扫一遍目录,stat 是顺带的,之后全是内存里的文本操作。取舍是快照文件占几十 MB 临时空间,而且时间戳精度依赖文件系统,APFS 和 ext4 的 %T@ 小数位不一致,跨平台比对要截断到秒。
失效的地方有三个。第一,路径里有制表符或换行会直接打乱列,我的 meta 目录里恰好没有,但加文件时得约定命名。第二,join 要求两边已排序且分隔符一致,索引文件如果是逗号分隔,得先转换,我踩过一次,结果全是假差异。第三,索引里的时间戳是「上次校验时」的,如果某次校验中途失败没写回,下一次会把整批文件误判为已变更,所以我在写回前先落一个 .done 标记,只认带标记的索引。
现在全量校验稳定在 50 秒上下,增量场景只跑 comm 那一步,几秒出结果。剩下没解决的是掉线挂载点导致的误报,我暂时用白名单压着。你们在 meta 这种带索引的目录上,是怎么处理挂载点抖动带来的假变更的?
0 条评论
还没有评论,写下第一条。