mkdir 的原子性
Atomicity of mkdir
我在 NFS v3 文件系统上遇到了一个奇怪的问题(我觉得这很重要)运行 两个进程并行执行(根据下面的评论和我自己对这件事的了解)不认为语言应该重要,我认为这足够可读):
if { ! [file isdirectory $dir]} {
if {[catch { file mkdir $dir} err]} {
error "-E- failed to mkdir $dir: $err"
}
}
对于那些不熟悉的人,tcl 中的 file mkdir
的行为与 mkdir -p
非常相似 - 只有目录存在且不是目录时才会失败。我几乎 100%(从来没有 100%)在任何进程中都没有创建该文件,只有 file mkdir
。问题并不总是发生,但经常发生 运行 我们的回归可能会遇到:
Error: can't create directory "$dir": file already exists
如果在 file mkdir
处理过程中 $dir
是一个现有的非目录文件,这应该 仅 发生。两个问题,第一个对我来说比较重要:
- mkdir 在这里不是原子的吗?特别是文件系统中的文件节点在创建期间是否可以作为非目录存在任意时间?
- 假设这确实是错误,是否有一种简单的原子方法可以做到这一点?我考虑过
exec mkdir -p
,但如果我是对的,这将遇到同样的问题。
重现这个问题已经够难了,所以我宁愿在尝试修复之前尽可能确定。我是在跟随 hint 之后来到这里的,该 hint 说 nfs
FS 可能是问题所在,但我需要更多专家建议。我不在乎两者是否成功,我只是不希望它们失败(第一次尝试)。
最后的笔记
我在很长一段时间后又回到了这个问题 - 这确实是一个 tcl 问题,但不仅仅是在 nfs 上, 尽管 nfs 似乎使它变得更糟!
仍在寻找解释为什么我看到我所看到的答案的答案 - 查看答案。
将其作为错误打开
https://core.tcl.tk/tcl/tktview/270f78ca95b642fbed81ed03ad381d64a0d0f7df
错误已修复!
tcl core的人真快!
TCL core 的小伙伴们在我发布错误后的第二天就修复了这个问题!
https://core.tcl.tk/tcl/tktview/270f78ca95b642fbed81ed03ad381d64a0d0f7df
已在 1c12ee9e45222d6c 中修复。
感谢 mrcalvin 的建议。
旧的测试尝试:
过了很长一段时间后,我又回到了这里,并进行了以下测试(在 ext4
上):
两个终端 tclsh
:
1: while {1} {file mkdir bla}
2: while {1} {file mkdir bla; file delete bla}
最终在 1:
上出错:
can't create directory "bla": no such file or directory
两个终端 tclsh
:
1: while {1} {exec mkdir -p bla}
2: while {1} {exec mkdir -p bla; file delete bla}
没有错误。
一个终端Bash一个tclsh
:
1: while [ 1 ]; do mkdir -p bla; done
2: while {1} {file mkdir bla; file delete bla}
最后我上了 1:
:
mkdir: cannot create directory ‘bla’: File exists
但奇怪的是
1: while [ 1 ]; do mkdir -p bla; rm -rf bla; done
2: while {1} {file mkdir bla}
没有错误(删除是罪魁祸首?)和
1: while [ 1 ]; do mkdir -p bla; done
2: while {1} {exec mkdir -p bla; file delete bla}
错误几率大大降低(所以删除不是那么糟糕?)。当然两个bash
shell不会冲突:
1: while [ 1 ]; do mkdir -p bla; rm -rf bla; done
2: while [ 1 ]; do mkdir -p bla; done
在 NFS 上但不在 EXT4 上
1: while {1} {file mkdir bla; exec rm -rf bla}
2: while {1} {file mkdir bla}
失败
can't create directory "bla": file already exists
两个 1:
2:
(随机)。
结论
file mkdir
并不像我想象的那样 "thin" 一层,并且会产生竞争条件,其中 mkdir
认为正在创建的目录是一个文件。 file delete
也可能有这个或类似的问题。它也可能导致我的测试失败,但不是我最初的问题 - NFS 系统的情况更糟,其中 file mkdir
单独很容易重现错误。
解决方法是使用exec mkdir -p
。到目前为止,这对我们来说是全面的。
我在 NFS v3 文件系统上遇到了一个奇怪的问题(我觉得这很重要)运行 两个进程并行执行(根据下面的评论和我自己对这件事的了解)不认为语言应该重要,我认为这足够可读):
if { ! [file isdirectory $dir]} {
if {[catch { file mkdir $dir} err]} {
error "-E- failed to mkdir $dir: $err"
}
}
对于那些不熟悉的人,tcl 中的 file mkdir
的行为与 mkdir -p
非常相似 - 只有目录存在且不是目录时才会失败。我几乎 100%(从来没有 100%)在任何进程中都没有创建该文件,只有 file mkdir
。问题并不总是发生,但经常发生 运行 我们的回归可能会遇到:
Error: can't create directory "$dir": file already exists
如果在 file mkdir
处理过程中 $dir
是一个现有的非目录文件,这应该 仅 发生。两个问题,第一个对我来说比较重要:
- mkdir 在这里不是原子的吗?特别是文件系统中的文件节点在创建期间是否可以作为非目录存在任意时间?
- 假设这确实是错误,是否有一种简单的原子方法可以做到这一点?我考虑过
exec mkdir -p
,但如果我是对的,这将遇到同样的问题。
重现这个问题已经够难了,所以我宁愿在尝试修复之前尽可能确定。我是在跟随 hint 之后来到这里的,该 hint 说 nfs
FS 可能是问题所在,但我需要更多专家建议。我不在乎两者是否成功,我只是不希望它们失败(第一次尝试)。
最后的笔记
我在很长一段时间后又回到了这个问题 - 这确实是一个 tcl 问题,但不仅仅是在 nfs 上, 尽管 nfs 似乎使它变得更糟!
仍在寻找解释为什么我看到我所看到的答案的答案 - 查看答案。
将其作为错误打开
https://core.tcl.tk/tcl/tktview/270f78ca95b642fbed81ed03ad381d64a0d0f7df
错误已修复!
tcl core的人真快!
TCL core 的小伙伴们在我发布错误后的第二天就修复了这个问题!
https://core.tcl.tk/tcl/tktview/270f78ca95b642fbed81ed03ad381d64a0d0f7df
已在 1c12ee9e45222d6c 中修复。
感谢 mrcalvin 的建议。
旧的测试尝试:
过了很长一段时间后,我又回到了这里,并进行了以下测试(在 ext4
上):
两个终端 tclsh
:
1: while {1} {file mkdir bla}
2: while {1} {file mkdir bla; file delete bla}
最终在 1:
上出错:
can't create directory "bla": no such file or directory
两个终端 tclsh
:
1: while {1} {exec mkdir -p bla}
2: while {1} {exec mkdir -p bla; file delete bla}
没有错误。
一个终端Bash一个tclsh
:
1: while [ 1 ]; do mkdir -p bla; done
2: while {1} {file mkdir bla; file delete bla}
最后我上了 1:
:
mkdir: cannot create directory ‘bla’: File exists
但奇怪的是
1: while [ 1 ]; do mkdir -p bla; rm -rf bla; done
2: while {1} {file mkdir bla}
没有错误(删除是罪魁祸首?)和
1: while [ 1 ]; do mkdir -p bla; done
2: while {1} {exec mkdir -p bla; file delete bla}
错误几率大大降低(所以删除不是那么糟糕?)。当然两个bash
shell不会冲突:
1: while [ 1 ]; do mkdir -p bla; rm -rf bla; done
2: while [ 1 ]; do mkdir -p bla; done
在 NFS 上但不在 EXT4 上
1: while {1} {file mkdir bla; exec rm -rf bla}
2: while {1} {file mkdir bla}
失败
can't create directory "bla": file already exists
两个 1:
2:
(随机)。
结论
file mkdir
并不像我想象的那样 "thin" 一层,并且会产生竞争条件,其中 mkdir
认为正在创建的目录是一个文件。 file delete
也可能有这个或类似的问题。它也可能导致我的测试失败,但不是我最初的问题 - NFS 系统的情况更糟,其中 file mkdir
单独很容易重现错误。
解决方法是使用exec mkdir -p
。到目前为止,这对我们来说是全面的。