2015-04-17 3 views
1

Я хотел бы читать и записывать файл атомарно в Ruby между несколькими независимыми процессами Ruby (а не потоками).Чтение и запись файла атомарно

  • Я нашел atomic_write от ActiveSupport. Это записывается в временный файл, затем перемещает его по оригиналу и устанавливает все разрешения. Однако это не мешает чтению файла во время его написания.
  • Я не нашел ни одного atomic_read. (Являются ли чтение файлов уже атомарным?)

Нужно ли мне реализовать собственный отдельный файл блокировки, который я проверяю перед чтением и записью? Или есть лучший механизм, уже присутствующий в файловой системе для того, чтобы пометить файл как «занятый», который я мог проверить перед любым чтением/записью?


Мотивация немой, но включен здесь, потому что вы собираетесь спросить об этом.

У меня есть веб-приложение, использующее Sinatra и обслуживается Thin, который (по его собственным причинам) использует файл JSON в качестве «базы данных». Каждый запрос на сервер считывает последнюю версию файла, вносит необходимые изменения и записывает изменения в файл.

Это было бы хорошо, если бы у меня был только один экземпляр сервера. Тем не менее, я думал о том, что несколько экземпляров Thin работают за обратным прокси-сервером Apache. Это отдельные процессы Ruby и, таким образом, работают по-настоящему параллельно.

При дальнейших размышлениях я понимаю, что я действительно хочу совершить акт чтения-процесса-записи атома. В этот момент я понимаю, что это в основном заставляет меня обрабатывать только один запрос за раз, и, следовательно, нет причин для запуска нескольких экземпляров. Но любопытство в отношении атомных чтений и предотвращение чтения во время записи остается. Отсюда вопрос.

+1

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

ответ

1

Вы хотите использовать File#flock в эксклюзивном режиме. Вот небольшая демонстрация. Запустите это в двух разных терминальных окнах.

filename = 'test.txt' 

File.open(filename, File::RDWR) do |file| 
    file.flock(File::LOCK_EX) 

    puts "content: #{file.read}" 
    puts 'doing some heavy-lifting now' 
    sleep(10) 
end 
+0

Спасибо, это отлично выглядит. Когда освобожден замок? Когда дескриптор файла закрыт? Кроме того, в документации указано, что «не доступно на всех платформах». Вы знаете, какие платформы он/недоступен? – Phrogz

+0

Я полагаю. Но вы можете разблокировать явно, вызывая 'file.flock (File :: LOCK_UN)' –

+0

Что касается поддержки платформы: я * думаю * это то, что у unixes было бы. Возможности, как правило, не работают на окнах, но я сделал аналогичную вещь на окнах ~ 10 лет назад. Однако не в рубине, но тогда у ОС были возможности. Вы должны попробовать :) –