Лучший способ атомарно создавать файлы

«Лучшая практика» (на мой взгляд) для атомарного создания нового файла — открыть временный файл (используя tmpfile()), а затем переместить файл в его окончательное местоположение.

Однако это не сработает, если временный файл находится в другой точке монтирования, так как это приведет к постепенному созданию файла и, кроме того, к ненужным издержкам ввода-вывода.

Другой вариант — создать временный файл в том же каталоге, что и конечный пункт назначения, но это имеет тот недостаток, что создает необычный файл для пользователя (такие приложения, как MS Word и ViM, делают это, но я также считаю это плохим поведением).

Есть ли метод, аналогичный tmpfile(), который позволит мне указать точку монтирования? Я понимаю, что это, вероятно, не существует встроенного в PHP, поэтому также допустима функция Posix/C или вызов оболочки.


person Evert    schedule 24.08.2009    source источник


Ответы (4)


Протокол maildir, разработанный для qmail, обеспечивает безопасное создание файлов несколькими средствами записи в один и тот же целевой каталог. , даже через NFS. В этой схеме каталог «tempfile» гарантированно находится в той же файловой системе, что и целевой каталог.

Алгоритм удобно реализован в эффективной утилите-оболочке safecat, man-страница представляет алгоритм как:

safecat применяет алгоритм maildir, записывая данные в шесть шагов. Во-первых, он выполняет stat() для двух каталогов tempdir и destdir и завершает работу, если оба каталога не существуют и не доступны для записи. Во-вторых, он stat() представляет имя tempdir/time.pid.host, где время — количество секунд с начала 1970 года по Гринвичу, pid — идентификатор процесса программы, а host — имя хоста. В-третьих, если stat() возвращает что-либо, кроме ENOENT, программа приостанавливается на две секунды, обновляет время и снова пробует stat() ограниченное количество раз. В-четвертых, программа создает tempdir/time.pid.host. В-пятых, программа NFS записывает сообщение в файл. В-шестых, программа связывает файл с каталогом destdir/time.pid.host. В этот момент данные были успешно записаны.

Кроме того, safecat запускает 24-часовой таймер перед созданием tempdir/time.pid.host и прерывает запись, если таймер истекает. В случае ошибки, тайм-аута или нормального завершения safecat пытается выполнить unlink() tempdir/time.pid.host.

person pilcrow    schedule 26.08.2009

Нет, такого метода в стеке POSIX нет. tmpfile() и tmpname() используют обычный временный каталог. Существует tempnam(), где вы можете указать целевой каталог для временного файла. Но это в основном способ реализовать второй вариант, который вы описали.

person dmeister    schedule 24.08.2009
comment
Мне было любопытно, есть ли какой-нибудь способ открыть INode и указать только имя файла в будущем. Я знаю, что можно открывать файлы, отсоединять файлы, а затем продолжать писать. - person Evert; 24.08.2009
comment
Я не думаю, что это возможно, но было бы неплохо знать точно. Если я не ошибаюсь, я посмотрю исходный код VFS. - person dmeister; 25.08.2009

Поскольку вы говорите о «точке монтирования», я предполагаю, что вы находитесь в Unix-подобной среде.

Возможно, вы можете считать это обходным путем или плохим поведением, но я думаю, что создание скрытого временного файла (.tmpfile) в той же папке назначения может быть приемлемым.

Конечно, вы можете создать определенную папку в той же точке монтирования, недоступную для приложения, подходящего для этой задачи, имитируя таким образом tempfile() в той же точке монтирования, если вы не хотите видеть какой-либо ложный файл в целевом каталоге. .

person drAlberT    schedule 24.08.2009
comment
На самом деле это мой второй вариант, которого я бы предпочел избежать. - person Evert; 24.08.2009
comment
@Thorarin, не могли бы вы дать мне больше информации об этом. Спасибо. - person drAlberT; 24.08.2009

Мне пришлось сделать что-то подобное, и я выбрал базу данных MySQL. Просто сохранил нужную мне информацию в таблице, и когда я закончил, я просто удалил запись. Просто мысль :)

person Phill Pafford    schedule 24.08.2009
comment
Однако это может привести к аналогичному количеству накладных расходов на ввод-вывод. Часто база данных даже не находится на том же сервере. - person Thorarin; 24.08.2009
comment
Использование MySQL определенно хуже - person Evert; 24.08.2009