【问题标题】:How to avoid a possible missing cache file in PHP?如何避免 PHP 中可能丢失的缓存文件?
【发布时间】:2012-11-07 17:38:42
【问题描述】:

我有一个简单的缓存系统

if (file_exists($cache)) {
echo file_get_contents($cache);
// if coming here when $cache is deleting, then nothing to display
}
else {
// PHP process
}

我们会定期删除过期的缓存文件,例如1小时后删除所有缓存。虽然这个过程非常快,但我认为可以在if statementfile_get_contents 进程之间删除缓存文件。

我的意思是当if statement检查缓存文件是否存在时,它存在;但是当file_get_contents 试图捕捉它时,它不再存在(被同步缓存删除过程删除)。

file_get_contents 锁定文件以避免在读取过程中进行删除过程。但是当if statement将PHP进程发送到第一个条件(file_get_contents开始之前)时,文件可以被删除。

有什么方法可以避免这种情况吗?缓存删除系统不一样吗?

注意:我没有遇到任何实际问题,因为捕获此事件的可能性不大,但从逻辑上讲这是可能的,并且应该在重负载时发生。

【问题讨论】:

  • 看看php.net/manual/en/function.flock.php - 如果您的检查过程和删除过程都需要排他锁,那么它们不能同时运行。
  • @andrewsi file_get_contents 锁定文件以供读取,但 if statement 不会。文件锁保证读取时文件不会被删除,但是有没有保证在'if statement返回true之后文件不会被删除?
  • 经典比赛条件。谷歌互斥和信号量。要么按照 andrewsi 的建议锁定,要么悲观地重新生成缓存文件,而不是真正需要。
  • @All - 在你的 if 语句之前获得一个独占锁,然后释放它。如果您的删除过程也在寻找独占锁,则它必须等到现有的锁被释放后才能运行。 flock 是一个非常有用的函数。
  • @andrewsi 这可能是一个实用的解决方案。它在缓存系统中很常见吗?我很好奇为什么没有关注这个可能的问题,而我错过了什么?

标签: php caching if-statement file-get-contents


【解决方案1】:

幸运的是 file_get_contents 出错时返回 FALSE,所以你可以像这样快速烘焙它:

if (FALSE !== ($buffer = file_get_contents())) {
    echo $buffer;
    return;
}
// PHP process

或类似的。考虑到您想放置 @ 运算符来隐藏有关不存在文件的任何警告,这有点快速和肮脏:

if (FALSE !== ($buffer = @file_get_contents())) {

另一种选择是锁定,但是如果您已锁定文件,这可能会阻止您的缓存删除删除文件。

然后剩下的是你自己的缓存。这意味着在 PHP 中读取文件创建时间,检查它是否小于 5 分钟,然后进行文件删除处理(5 分钟是示例性的),然后您就会知道该文件已经过时并被替换为新内容。然后重新创建文件。否则读入文件,这可能比使用readfile 而不是file_get_contentsecho 更好。

【讨论】:

    【解决方案2】:

    如果失败,file_get_contents 会返回 false,那么这个呢:

    if (($output = file_get_contents($filename)) === false){
      // Do the processing.
      $output = 'Generated content';
      // Save cache file
      file_put_contents($filename, $output);
    }
    echo $output;
    

    顺便说一句,您可能需要考虑使用fpassthru,它更节省内存,尤其是对于较大的文件。对大文件(> 100 MB)使用 file_get_contents 可能会导致问题(取决于您的配置)。

    <?php
    $fp = @fopen($filename, 'rb');
    if ($fp === false){
      // Generate output
    } else {
      fpassthru($fp);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-19
      • 1970-01-01
      • 2020-06-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多