【问题标题】:Atomically file_get_contents + file_put_contents原子地 file_get_contents + file_put_contents
【发布时间】:2015-07-20 02:49:02
【问题描述】:

我有一段代码可以将 CSV 日志文件截断到指定的尾随时间段。每个 CSV 条目中的第一个字段是时间戳。

以下内容会正确清除,但不会自动截断日志,从而导致 file_get_contents 和 file_put_contents 之间丢失的日志条目可能丢失。由于新条目位于文件底部,因此在此之前没有损坏日志的风险。

我考虑在 file_get_contents 和 file_put_contents 中手动执行操作,但 PHP 文档声称这些操作做了各种超级有趣的巫毒优化,并且是做我想做的事情的推荐方法(将所有文件内容作为字符串并填充一个带有字符串的文件),所以我很好奇是否有一种方法可以在不安全的情况下使用这些函数。

$time = time();
$fp = @fopen( $file, 'r' );
if ( $fp !== false ) {
    $truncate = false;
    $offset   = 0;

    // find the first non-expired entry
    while ( ( $fields = fgetcsv( $fp ) ) !== false ) {
        if ( ! is_null( $fields ) && $time > ( $fields[0] + $purge_interval ) ) {
            // we've reached the recent entries -- nothing beyond here will be removed
            break;
        }

        $offset   = @ftell( $fp );
        if ( false === $offset ) {
            break;
        }

        $truncate = true;
    }

    @fclose( $fp );

    if ( $truncate ) {
        // need the next two lines atomically performed...
        $data = file_get_contents( $file, false, null, $offset );
        file_put_contents( $file, $data, LOCK_EX );
    }
}

【问题讨论】:

  • 您是否也可以控制使用日志的所有其他代码?
  • 我愿意。满足最小尺寸要求的更多字...

标签: php file-io atomic


【解决方案1】:

没有像这样进行就地并发修改的万无一失的方法。该过程必须删除这些属性之一才能实现。

由于您还控制日志写入者,一个简单而好的解决方案是放弃绝对并发并与flock同步对日志的访问。日志写入者会定期打开日志以附加到它,并且它们和截断进程也会在操作期间锁定日志文件。

例如,截断实用程序会这样做

if (flock($fp, LOCK_EX)) {
    $data = file_get_contents( $file, false, null, $offset );
    file_put_contents( $file, $data, LOCK_EX );
    flock($fp, LOCK_UN);
}

日志写入者也会在写入文件之前获取锁。有趣的一点是,作者可能更愿意尝试非阻塞锁,并且如果忙于继续将日志存储在内存中,以免在未知时间内阻塞进程;在这种情况下,将定期再次尝试该过程。

【讨论】:

    【解决方案2】:

    我认为日志文件遵循“追加,只写”的模式是有原因的:很难让它们同时具有高性能和可编辑性。这就是为什么通常的日志文件会通过 cron 作业在文件系统中自动轮换,以允许切断旧部分,可能压缩或最终删除它,同时允许将新数据存储在新文件中。

    所以我会尝试通过使用单独的文件将日志条目的创建与处理它们分开。每天或每小时创建一个新的日志文件。新文件启动后处理旧文件。

    【讨论】:

      猜你喜欢
      • 2019-06-22
      • 2013-02-15
      • 1970-01-01
      • 1970-01-01
      • 2013-06-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多