2015-07-19 57 views
1

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

以下正确清除,但不是自动截断日志,导致可能失去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); 
    } 
} 
+0

你是否也控制了使用日志的所有其他代码?我做的是 – Jon

+0

。更多的话来满足最小尺寸要求... – Dan

回答

2

没有像这样的就地并发修改的防弹方法。该过程将不得不放弃其中一个属性才能实施。

既然您也控制日志编写器,一个简单而好的解决方案是放弃绝对并发并使用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); 
} 

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

+0

真棒的答案!谢谢! –

0

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

所以我试图分开创建日志条目,通过分离文件来处理它们。每天或每小时创建一个新的日志文件。新文件启动后处理旧文件。