Follow to : Как безопасно обновить файл, который имеет много читателей и один писатель?
В моих предыдущих вопросах я выяснил, что вы можете использовать блокировку FileChannel для обеспечения порядка чтения и записи.
Но как вы справляетесь со случаем, если писателю не удается в середине записи (скажем, сбой JVM)? Этот базовый алгоритм будет выглядеть так:
WRITER:
lock file
write file
release file
READER:
lock file
read file
release file
Если JVM дает сбой во время write file
, обязательно снимите блокировку, но теперь у меня есть неполный файл. Я хочу, чтобы что-то законченное всегда было читабельным. Либо старый контент, новый контент и ничего промежуточного.
Моя первая стратегия состояла в том, чтобы записать во временный файл, а затем скопировать содержимое в «живой» файл (при этом обеспечив хорошую блокировку). Алгоритм для этого,
WRITER:
lock temp file
write temp file
lock file
copy temp to file
release file
release temp
delete temp
READER:
lock file
read file
release file
Одна приятная вещь - delete temp
не удалит темп, если он уже заблокирован другим автором.
Но этот алгоритм не обрабатывает, если JVM дает сбой во время copy temp to file
. Затем я добавил флаг copying
,
WRITER:
lock temp file
write temp file
lock file
create copying flag
copy temp to file
delete copying flag
release file
release temp
delete temp
READER:
lock file
if copying flag exists
copy temp to file
delete copying flag
delete temp
end
read file
release file
Никогда не будет двух вещей, получающих доступ к файлу copying
, поскольку он защищен блокировкой файла.
Теперь, это способ сделать это? Кажется очень сложным обеспечить что-то очень простое. Есть ли какая-нибудь библиотека Java, которая обрабатывает это для меня?
EDIT
Ну, мне удалось ошибиться в третьей попытке. Читатель не удерживает блокировку температуры, когда он делает copy temp to file
. Также это не простое исправление, чтобы просто заблокировать временный файл! Это может привести к тому, что писатель и читатель получат блокировки в разных порядках и могут привести к тупику. Это становится все сложнее все время. Вот моя четвертая попытка,
WRITER:
lock file
write temp file
create copying flag
copy temp to file
delete copying flag
delete temp
release file
READER:
lock file
if copying flag exists
copy temp to file
delete copying flag
delete temp
end
read file
release file
На этот раз временный файл защищен основной блокировкой, поэтому ему даже не нужна собственная блокировка.
РЕДАКТИРОВАТЬ 2
Когда я говорю о сбое JVM, я на самом деле имею в виду, что питание отключилось, а у вас не было ИБП.
РЕДАКТИРОВАТЬ 3
Мне все-таки удалось сделать еще одну ошибку. Вы не должны блокировать файл, в который вы пишете или читаете. Это вызовет проблемы, поскольку вы не можете получить блокировку чтения и записи, если не используете RandomAccessFile в Java, которая не реализует поток ввода / вывода.
Вместо этого вы просто хотите заблокировать файл блокировки, который защищает файл, который вы читаете или записываете. Вот обновленный алгоритм:
WRITER:
lock
write temp file
create copying flag
copy temp to file
delete copying flag
delete temp
release
READER:
lock
if copying flag exists
copy temp to file
delete copying flag
delete temp
end
read file
release
блокирует и освобождает файл, временный файл и флаг копирования. Единственная проблема в том, что теперь блокировка считывателя не может быть разделена, но на самом деле это никогда не может быть. У читателя всегда была возможность изменить файл, поэтому было бы неправильно сначала создавать разделяемую блокировку.