Как сделать файловый ввод-вывод более транзакционным?

Я пишу сценарии CGI на Haskell. Когда пользователь нажимает «отправить», на сервере запускается программа Haskell, обновляющая (т.е. считывающая, обрабатывающая, перезаписывающая) файл состояния. Чтение с последующей перезаписью иногда вызывает проблемы с отложенным вводом-выводом, поскольку мы можем сгенерировать большой префикс вывода до того, как закончим чтение ввода. Хуже того, пользователи иногда нажимают кнопку отправки, и два экземпляра процесса запускаются одновременно, сражаясь за один и тот же файл!

Какой хороший способ реализовать

transactionalUpdate :: FilePath -> (String -> String) -> IO ()

, где функция ('update') вычисляет новое содержимое файла из старое содержимое файла? Небезопасно предполагать, что «обновление» является строгим, но можно предположить, что оно является полным (устойчивость к функциям частичного обновления является бонусом). Транзакции могут быть предприняты одновременно, но ни одна транзакция не должна обновляться, если файл был записан кем-либо еще с момента его чтения. Транзакция может быть прервана в случае конкуренции за доступ к файлам. Мы можем предположить, что это источник уникальных для всей системы временных имен файлов.

Моя текущая попытка записывает во временный файл, а затем использует команду системного копирования для перезаписи. Кажется, это решает проблемы ленивого ввода-вывода, но это не кажется мне безопасным от гонок. Есть ли проверенная формула, которую мы могли бы просто разлить в бутылки?

18
задан pigworker 14 August 2011 в 19:46
поделиться