php file_put_contents 偶尔没有那个文件或目录
php file_put_contents no such file or directory occasionally
我启动了8个进程来执行一个作业,作业中的代码是这样的:
<?php
$dir = "/home/test/fileputcontents/0";
if(! is_dir($dir)){
mkdir($dir, 0755, true);
}
file_put_contents("{$dir}/0.txt", "aaaa\n", FILE_APPEND | LOCK_EX);
但有时会出现“没有这样的文件或目录”的错误,不是很频繁,非常感谢。
是因为php_mkdir_ex方法吗?多进程同时创建目录
/* DEPRECATED APIs: Use php_stream_mkdir() instead */
PHPAPI int php_mkdir_ex(const char *dir, zend_long mode, int options)
{
int ret;
if (php_check_open_basedir(dir)) {
return -1;
}
if ((ret = VCWD_MKDIR(dir, (mode_t)mode)) < 0 && (options & REPORT_ERRORS)) {
php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
}
return ret;
}
是否所有 8 个进程 运行 同时写入同一个文件?如果两个进程同时写入文件,则文件可能被锁定(由 LOCK_EX 标志引起)。所以一个进程会获胜(可以写入文件)而另一个进程不会等待,而是会引发错误。
终于从php源码中找到了原因。这是因为目录创建冲突。例如:
- 我们有 2 个进程同时创建目录“/home/test/fileputcontents/0”。
- 现在只有
/home
目录存在,我们需要创建test/fileputcontents/0
- 一个进程(我们称为A)已经创建了
test
,即将创建fileputcontents
,另一个进程(我们称为B)将再次创建test
,但是它已经存在。
- 然后进程 B 停止创建目录,因为它认为所有目录都存在
- 当 B 试图在 A 创建所有目录之前调用
file_put_contents
时,它会警告 "No such file or directory"
,因为 fileputcontents/0
不存在。
我的解决方案,创建目录,因为进程启动。
已在 8.1 中修复
https://github.com/php/php-src/pull/7383
- if (ret < 0) {
+ if (ret < 0 && errno != EEXIST) {
我启动了8个进程来执行一个作业,作业中的代码是这样的:
<?php
$dir = "/home/test/fileputcontents/0";
if(! is_dir($dir)){
mkdir($dir, 0755, true);
}
file_put_contents("{$dir}/0.txt", "aaaa\n", FILE_APPEND | LOCK_EX);
但有时会出现“没有这样的文件或目录”的错误,不是很频繁,非常感谢。
是因为php_mkdir_ex方法吗?多进程同时创建目录
/* DEPRECATED APIs: Use php_stream_mkdir() instead */
PHPAPI int php_mkdir_ex(const char *dir, zend_long mode, int options)
{
int ret;
if (php_check_open_basedir(dir)) {
return -1;
}
if ((ret = VCWD_MKDIR(dir, (mode_t)mode)) < 0 && (options & REPORT_ERRORS)) {
php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
}
return ret;
}
是否所有 8 个进程 运行 同时写入同一个文件?如果两个进程同时写入文件,则文件可能被锁定(由 LOCK_EX 标志引起)。所以一个进程会获胜(可以写入文件)而另一个进程不会等待,而是会引发错误。
终于从php源码中找到了原因。这是因为目录创建冲突。例如:
- 我们有 2 个进程同时创建目录“/home/test/fileputcontents/0”。
- 现在只有
/home
目录存在,我们需要创建test/fileputcontents/0
- 一个进程(我们称为A)已经创建了
test
,即将创建fileputcontents
,另一个进程(我们称为B)将再次创建test
,但是它已经存在。 - 然后进程 B 停止创建目录,因为它认为所有目录都存在
- 当 B 试图在 A 创建所有目录之前调用
file_put_contents
时,它会警告"No such file or directory"
,因为fileputcontents/0
不存在。
我的解决方案,创建目录,因为进程启动。
已在 8.1 中修复
https://github.com/php/php-src/pull/7383
- if (ret < 0) {
+ if (ret < 0 && errno != EEXIST) {