nfs
Неблокирующий режим файлов в PHP
Позже я внимательно прочитал документацию на теме. По всей видимости, это ничего не даст в отношении проверки системы хранения на зависание.
Смотрел недавно исходники языка ПХП, хотел изучить подробнее как реализованы там стримы. Пока читал, случайно натолкнулся на недокументированную возможность — у функции fopen, как оказалось, есть режим открытия в неблокирующем режиме (буква n).
#if defined(O_NONBLOCK)
if (strchr(mode, 'n')) {
flags |= O_NONBLOCK;
}
#endifДоступно не на всех системах, только там, где есть константа O_NONBLOCK в fcntl.h, то есть в Линуксах, например.
Для меня это довольно полезное знание, так как я давно ищу возможность проверить из ПХП не зависла ли подмонтированная через NFS система хранения.
В общем, надо будет попробовать при следующем таком инциденте — не спасает ли открытие в неблокирующем режиме. Код, кажется, должен выглядеть примерно так:
function tryToOpen(string $path, float $timeout): ?bool
{
$dio_fd = dio_open($path, O_RDONLY | O_NONBLOCK);
if ($dio_fd === false) {
return null;
}
foreach (glob('/proc/self/fd/*') as $file) {
if (is_link($file) && readlink($file) === $path) {
$fd = basename($file);
$read = [fopen("php://fd/$fd", 'rn')];
$write = $except = null;
$timeout_us = (int) ($timeout * 1e6);
return stream_select($read, $write, $except, 0, $timeout_us) === 1;
}
}
return null;
}Тут используется модуль ПХП Direct IO, чтобы обратиться к системной функции open мимо ПХП. Приходится так делать, потому что функция fopen, которая есть в языке, сначала попытается проверить существование файла и в моей задаче сразу зависнет.
После этого я, пользуясь /proc, ищу среди своих файловых дескрипторов тот, который отвечает за только что открытый файл и переоткрываю его через fopen (в этом месте делается дубликат файлового дескриптора, а прежний закрывается — вызывается dup), так как мы тут работаем с номером файлового дескриптора, то проверка на существование файла не используется.
Переоткрытие файла нужно, так как в вызов stream_select, который я использую для ожидания данных из файла с таймаутом, можно передать результат fopen, но не dio_open.
Надеюсь случай испытать этот код представится нескоро.
Негативное кеширование NFS
В реализациях сетевой файловой системы NFS есть так называемое «негативное кеширование». Эта штука портит много крови программистам, а суть её проста, как чихание — если вы обратились за файлом и его на момент обращения не было, то
Например, вы обращаетесь через NFS за файлом и если его нет, даёте серверу очередей задание на генерацию. Дожидаетесь выполнения задания и снова пытаетесь найти файл по тому же пути. Если обработка задания заняла секунды, то
Теоретически этот кеш можно отключить (опцией lookupcache), практически же не всегда на оборудовании заказчика удаётся это сделать.
Чтобы решить эту проблему, мы придумывали разные сигнальные схемы и в ходе экспериментов обнаружилось, что если
function clear_nfs_cache(string $filename): bool
{
$tmpname = tempnam(dirname($filename), 'clear-cache'));
return $tmpname === false ? false : unlink($tmpname);
}