Okazało się, że jest to spowodowane warunkami wyścigowymi. cp
sprawdza, czy plik docelowy już istnieje, a jeśli nie - zastępuje go. Problem występował, ponieważ to cp
polecenie było uruchamiane dwukrotnie równolegle, co powodowało, że dany plik czasami pojawiał się po sprawdzeniu, czy istnieje, ale przed próbą utworzenia pliku. Dane strace
wyjściowe wyglądają następująco:
# Command was "cp a b"
stat("b", 0x7fff89510620) = -1 ENOENT (No such file or directory)
stat("a", {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
stat("b", 0x7fff895103a0) = -1 ENOENT (No such file or directory)
# File b will be created at this point in time
open("a", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
open("b", O_WRONLY|O_CREAT|O_EXCL, 0644) = -1 EEXIST (File exists)
Oto kod bash używany do tego:
#!/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
Ten sam błąd może wystąpić podczas mkdir -p
dowolnej akcji, która próbuje zastąpić plik. Używanie flock
może pomóc w uniknięciu warunków wyścigowych w takich przypadkach.
||
operatora. Coś w rodzaju próbowania / połowu przez robaka. Tjcp ... || echo "skip copying due to other thread"
. Lub coś podobnego ...cp
cp
.