У меня есть мобильное приложение, которое читает JSON-файл, который хранится на сервере Apache. Содержимое этого файла JSON восстанавливается (с использованием PHP-скрипта), если что-то изменяется с помощью графического интерфейса пользователя.
Я беспокоюсь, что попытка перезаписать JSON-файл в середине его обслуживания Apache может вызвать проблемы.
Доступет ли Apache блокировку чтения перед подачей файлов? Если нет, что произойдет, если я попытаюсь написать его, в то же время он будет подан?
Нет. В POSIX-совместимых системах все блокировки в любом случае являются рекомендательными, поэтому даже если apache получит блокировку чтения, другой процесс может просто записать файл.
Вы можете определить, что с strace
:
[pid 7246] open("/var/www/file.json", O_RDONLY|O_CLOEXEC) = 11 [pid 7246] fcntl(11, F_GETFD) = 0x1 (flags FD_CLOEXEC) [pid 7246] mmap(NULL, 20, PROT_READ, MAP_SHARED, 11, 0) = 0x7f53f93da000 [pid 7246] munmap(0x7f53f93da000, 20) = 0 [pid 7246] writev(10, [{"HTTP/1.1 200 OK\r\nDate: Thu, 26 J"}, ...) = 365 [pid 7246] close(11) = 0
Поэтому может случиться так, что ваш файл JSON будет только частично записан. Чтобы избежать этой проблемы, напишите свой файл JSON во временный файл в той же файловой системе и используйте атомное rename
для перезаписывания файла.
Таким образом, если open
преуспел, apache продолжит обслуживать старый файл. Если rename
закончится до open
, apache получит новый, завершенный файл.
Если вы беспокоитесь о согласованности (в случае сбоя питания или так), вы также можете вызвать fsync
в приложении, которое записывает файл JSON, прежде чем закрывать его.
Вы думаете о неправильной парадигме для платформ nix. Вы хотите, чтобы файл Atom записывался в файл JSON в вашем скрипте. Вы делаете это, записывая файл в уникальное временное имя файла в целевом каталоге, а затем rename()
чтобы переместить этот файл поверх старого. Операция перемещения файла является атомарной. Асинхронные процессы либо откроют старый файл JSON, либо новый, но не гибрид.
Существуют различные способы создания временного имени файла. См. Комментарии пользователя документации PHP на tempnam()
. Моя система генерирует уникальный идентификатор запроса, поэтому я просто использую $_SERVER["UNIQUE_ID"]
в качестве базы.