создание атомарного файла в Linux?

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

Я читал о флаге O_EXCL для open(), поэтому кажется, что решение существует, однако у меня есть несколько вопросов:

  1. у вас есть опыт работы с этой техникой? Насколько это хорошо? (Думаю, у меня не может быть атомарности на уровне БД, но достаточно хорошо... ну, достаточно)
  2. мне сразу после open() закрыть файл, чтобы он считался созданным, а потом снова открыть для записи?
  3. есть ли какие-то тонкости, о которых стоит знать?

person davka    schedule 06.03.2011    source источник


Ответы (2)


На справочной странице open() говорится, что ваш метод может дать сбой в NFS.

Из раздела O_EXCL:

При использовании с O_CREAT, если файл уже существует, это ошибка, и open() завершится ошибкой. В этом контексте символическая ссылка существует независимо от того, куда она указывает. O_EXCL не работает в файловых системах NFS; программы, которые полагаются на него для выполнения задач блокировки, будут содержать состояние гонки.

И это предлагает более общее решение:

Решение для выполнения атомарной блокировки файлов с помощью файла блокировки состоит в том, чтобы создать уникальный файл в той же файловой системе (например, включая имя хоста и pid), использовать link(2) для создания ссылки на файл блокировки. Если link() возвращает 0, блокировка прошла успешно. В противном случае используйте stat(2) для уникального файла, чтобы проверить, увеличилось ли количество его ссылок до 2, и в этом случае блокировка также будет успешной.

См. раздел «Использование файлов в качестве замков» на этой веб-страницы. для получения более подробной информации о различных проблемах и подходах.

person payne    schedule 06.03.2011
comment
да, я видел это, поэтому мои вопросы были на случай, если я не работаю с NFS. Кроме того, альтернативное решение для меня неясно - как создание уникального файла для каждого процесса помогает двум процессам увидеть, что они пытаются работать с одним и тем же файлом? Если вы понимаете это, не хотите объяснить? - person davka; 06.03.2011
comment
вызовы link и unlink в NFS не являются идемпотентными или синхронизированными. Вместо этого используйте mkdir. - person tchrist; 06.03.2011
comment
@davka: этот метод использует ссылку в качестве блокировки. Независимо от того, на какой файл в данный момент указывает ссылка, он владеет блокировкой. (И каждый файл уникален для процесса, поэтому у вас есть блокировка процесса). - person payne; 06.03.2011
comment
@davka — fcntl должен работать через NFS, поэтому в качестве альтернативы вы можете использовать чтобы синхронизировать ваши процессы при записи, а не при открытии. - person aaz; 06.03.2011

POSIX говорит:

Если установлены O_CREAT и O_EXCL, open() завершится ошибкой, если файл существует. Проверка существования файла и создание файла, если он не существует, должны быть атомарными по отношению к другим потокам, выполняющим open() с тем же именем файла в том же каталоге с установленными O_EXCL и O_CREAT.

Таким образом, другие процессы, использующие O_EXCL, будут считать его открытым, как только он будет создан.

person aaz    schedule 06.03.2011
comment
спасибо, это более однозначно. Погуглил, считается ли файл созданным сразу после open(). Кажется, это говорит о том, что да - person davka; 06.03.2011
comment
@davka - я думаю, там написано да, должно быть, но я не вижу смысла вообще иметь флаг без этой гарантии. справочные страницы BSD говорят, что это может использоваться для реализации простого монопольного механизм блокировки доступа. Без гарантии это не сработает. - person aaz; 06.03.2011