Как надежно обновить файл в общей файловой системе?

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

  • Актуальный файл для обновления: MyFile.json
  • Temp файл для записи: tmp~MyFile.json{timestamp}~tmp
  • Блокировка файла для блокировки: MyFile.json#LOCK

Для этого нам, кажется, нужны три имени файла. Фактическое имя файла, которое мы обновляем. Существует временный файл, в который записывается содержимое, а затем временный файл переименовывается в фактическое имя. Но я хочу удерживать блокировку все время, пока это происходит, поэтому для файла нулевой длины требуется третье имя файла, которое блокируется перед доступом к файлу и освобождается после завершения всего процесса.

Есть ли более простой способ сделать это?

Я предполагаю, что нет. Если я заблокирую фактическое имя файла, то я не смогу удалить его, чтобы переименовать временный файл в реальный файл. Я также не могу использовать расширенную команду IO Files.move для удаления и переименования атомарно. Если файл заблокирован, моя программа не может заменить файл. Поэтому вместо этого я блокирую файл блокировки токена, и по крайней мере все программы, подчиняющиеся этому протоколу, должны быть соответствующим образом синхронизированы.

Это протокол:

  1. Блокировка файла блокировки, блокировка до получения блокировки
  2. прочитать фактический файл
  3. напишите временный файл
  4. удаляя прежний фактический файл, и проверьте, что он удален
  5. переименуйте temp в фактический и убедитесь, что новый фактический файл существует.
  6. Разблокировать файл блокировки

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

Проблема, как представляется, заключается в том, что "разблокировка" сигнализируется другой системе быстрее, чем "переименование". Второй компьютер может получить блокировку, но переименованный файл еще не появляется на нем. Первый компьютер выполняет переименование, а затем выполняет разблокировку, но второй компьютер может получить блокировку до появления переименования.

Шаг 4 и 5 можно выполнить за один шаг, используя атомарное обновление Files.move, но я получаю те же результаты.

ВОПРОС: Есть ли способ убедиться, что второй компьютер не сможет получить блокировку, пока не появится переименование.

ВОПРОС: Есть ли способ заставить Windows пойти и проверить, действительно ли файл действительно там?

Источник доступен на GitHub:

LockableJSONFile: https://github.com/agilepro/mendocino/blob/master/src/com/purplehillsbooks/json/LockableJSONFile.java

Источник теста: https://github.com/agilepro/mendocino/blob/master/src/com/purplehillsbooks/testcase/FileLockTest.java

Если вы хотите проверить, вытащите весь модуль и скомпилируйте. Инструкции по запуску теста приведены по адресу: https://github.com/agilepro/mendocino/wiki/File-Locking-Test

В качестве предупреждения, сразу после блокировки на шаге 1, если файл не существует, метод блокировки ожидает 100 мс в надежде, что он обнаружится в это время. Я все еще получаю сбои... в некоторых редких случаях это, очевидно, занимает более 100 мс. Это действительно брутто. Я хочу знать, существует ли лучший, полностью надежный способ обеспечения эксклюзивного доступа к файлу в общей файловой системе.

0 ответов

Другие вопросы по тегам