• cp: 无法创建普通文件 : 文件已存在


    背景

    碰到一个偶现的编译出错问题,如图

    报错的信息是

    cp: 无法创建普通文件"xxx": 文件已存在
    

    排查原因

    看了下 Makefile,这句非常简单,就是 cp ./xxx ../xxx 而已,本身没什么问题。

    那再结合上下文出现的打印,一个异常之处就是 Makfeile 被并行重复执行了,猜测是并行导致 cp 操作出错。

    只考虑解决问题,那无疑是修改外层 Makefile ,避免此处被并行重复执行,至少这句 cp 不要被并行,就可以解决了。

    但为什么 cp 并行执行会出错呢?如果在另外的场景下确实有并行执行cp的可能,有没有办法规避这个错误呢?这就得探究下了。

    单独执行 cp,默认的行为就是覆盖已存在的文件,并不会因为 “文件已存在” 这样的原因出错,随便做下实验,touch a b; cp a b就可以确认正常是不会报错的。

    那问题还是得结合并行来分析,碰到这种情况,要么是从搜索资料获得提示,要么就是实践出真知,自己设计一个可快速复现的方式,然后使用调试工具来追踪问题发生时的具体情况。

    具体到这个问题,我是搜索到相同的stackexchange问题,那就省点工夫不用自己去复现分析了。

    这里插下题外话,搜索优先使用google,对于中文报错信息查不到的可改成英文查询。例如中文的 cp: 无法创建普通文件 文件已存在 就不好找到答案,换成 cp cannot create regular file file exists 就好找了。(只敲一部分,搜索引擎就能提示完整的信息)

    stackexchage上给出了一个脚本,用于复现问题并使用 strace 将追踪的系统调用记录下来

    #!/bin/bash
    
    touch a
    
    f() {
      while true; do
        rm -f b
        strace -o /tmp/cp${BASHPID}.trace cp a b || break
      done
    }
    
    cleanup() {
      kill -9 %1 %2
    }
    
    f &
    f &
    
    trap cleanup exit
    
    wait
    

    附上我自己的实验结果,可以看出cp的实现上,会先用stat来判断目标文件b是否存在,如果不存在则会使用 open("b", O_WRONLY|O_CREAT|O_EXCL, 0664) 来创建目标文件并将源文件写入目标文件,完成复制。

    那么如果两个 cp 并发,就可能出现

    cp1                  cp2
    stat判断b不存在     
                         stat判断b不存在
    open成功,创建文件b         
                         open失败,因为此时文件已经被cp1创建好了
    

    stracelog 看到的就是

    由于 cp 不是原子的,如果两个 cp 刚好几乎同时执行,则可能两个 cpstat都判断到文件不存在,那最终只有一个 cp 能创建文件,另一个就失败了。

    顺便看看,文件存在和不存在的open参数差异

    解决办法

    既然两个cp同时执行会出错,那就加锁呗。

    如果所有调用 cp 的地方都是我们可控的,那劝告锁就足够了,在 shell 中可以直接使用 flock

    约定好一个文件锁x, 将原来的cp a b 改成 flock x cp a b 即可。

    例如正常在两个控制台中,执行top是可以并行的,但如果改成执行 flock /tmp/toplock top,那就只有控制台1会执行top,控制台2则处于等待文件锁的状态。此时若控制台1退出top,则控制台2获得锁,开始执行top

    更多文件锁的细节,可以看看 man flock

    blog: https://www.cnblogs.com/zqb-all/p/12942556.html
    公众号:https://sourl.cn/S42YSr

  • 相关阅读:
    python-多任务-进程
    注解_Annotation
    ZIP压缩输入/输出流
    什么是API,这篇文章让你豁然开朗
    异常处理(在控制台输入数据)
    控件监听与面板监听
    多态与继承
    Java——socketser与cli
    20170307
    20180305
  • 原文地址:https://www.cnblogs.com/zqb-all/p/12942556.html
Copyright © 2020-2023  润新知