У меня есть файл журнала, поддерживаемый скриптом PHP. Скрипт PHP подвергается параллельной обработке. Я не могу заставить механизм flock()
работать с файлом журнала: в моем случае flock()
не препятствует одновременному доступу к файлу журнала, совместно используемому сценариями PHP, работающим параллельно, и иногда перезаписываемому.
Я хочу быть в состоянии прочитать файл, выполнить некоторую обработку, изменить данные и записать обратно без того же кода, работающего параллельно на сервере, выполняющего то же самое в то же время. Запись read модификации должна быть в последовательности.
На одном из моих общих хостингов (OVH France) он не работает должным образом. В этом случае мы видим, что счетчик $c
имеет одно и то же значение в разных iframe
с, что не должно быть возможно, если блокировка работает должным образом, как это происходит на другом виртуальном хостинге.
Любые предложения, чтобы сделать эту работу, или для альтернативного метода?
Googling "read modify write" php
или fetch and add
или test and set
не предоставили полезной информации: все решения основаны на рабочем стаде ().
Вот несколько автономных демонстрационных кодов для иллюстрации. Он генерирует ряд параллельных запросов от браузера к серверу и отображает результаты. Легко визуально наблюдать за дисфункцией: если ваш веб-сервер не поддерживает flock (), как у меня, значение счетчика и количество строк журнала будут одинаковыми в некоторых кадрах.
<!DOCTYPE html>
<html lang="en">
<title>File lock test</title>
<style>
iframe {
width: 10em;
height: 300px;
}
</style>
<?php
$timeStart = microtime(true);
if ($_GET) { // iframe
// GET
$time = $_GET['time'] ?? 'no time';
$instance = $_GET['instance'] ?? 'no instance';
// open file
// $mode = 'w+'; // no read
// $mode = 'r+'; // does not create file, we have to lock file creation also
$mode = 'c+'; // read, write, create
$fhandle = fopen(__FILE__ .'.rwtestfile.txt', $mode) or exit('fopen');
// lock
flock($fhandle, LOCK_EX) or exit('flock');
// start of file (optional, only some modes like require it)
rewind($fhandle);
// read file (or default initial value if new file)
$fcontent = fread($fhandle, 10000) or ' 0';
// counter value from previous write is last integer value of file
$c = strrchr($fcontent, ' ') + 1;
// new line for file
$fcontent .= "<br />\n$time $instance $c";
// reset once in a while
if ($c > 20) {
$fcontent = ' 0'; // avoid long content
}
// simulate other activity
usleep(rand(1000, 2000));
// start of file
rewind($fhandle);
// write
fwrite($fhandle, $fcontent) or exit('fwrite');
// truncate (in unexpected case file is shorter now)
ftruncate($fhandle, ftell($fhandle)) or exit('ftruncate');
// close
fclose($fhandle) or exit('fclose');
// echo
echo "instance:$instance c:$c<br />";
echo $timeStart ."<br />";
echo microtime(true) - $timeStart ."<br />";
echo $fcontent ."<br />";
} else {
echo 'File lock test<br />';
// iframes that will be requested in parallel, to check flock
for ($i = 0; $i < 14; $i++) {
echo '<iframe src="?instance='. $i .'&time='. date('H:i:s') .'"></iframe>'."\n";
}
}
В PHP есть предупреждение об flock()
ограничениях: flock - Manual , но это касается ISAPI (Windows) и FAT (Windows). Моя конфигурация сервера:
Версия PHP 7.2.5
Система: Linux cluster026.gra.hosting.ovh.net
Серверный API: CGI / FastCGI