Разблокировка и удаление файла как одна операция - PullRequest
1 голос
/ 19 декабря 2009

Обратите внимание, что это не является дубликатом блокировки файла и удаления файла . (Разница - платформа. Операции с файлами, такие как блокировка и удаление, имеют совершенно разную семантику, поэтому использование будет другим).

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

Я хочу следующий API: write(sid,data,timeout), read(sid,data,timeout), remove(sid) где sid == имя файла, также я хочу иметь какой-то GC, который может удалить все сеансы по тайм-ауту.

Довольно простая задача, если вы работаете с одним процессом, но абсолютно не тривиальная при работе с несколькими процессами или даже над общими папками.

Самое простое решение, о котором я думал, было:

write/read:
   hanlde=CreateFile
   LockFile(handle)
   read/write data
   UnlockFile(handle)
   CloseHanlde(handle)

GC (for each file in directory)
   hanlde=CreateFile
   LockFile(handle)
   check if timeout occured
     DeleteFile
   UnlockFile(handle)
   CloseHanlde(handle)

Но AFIAK Я не могу вызвать DeleteFile для открытого заблокированного файла (в отличие от Unix, где блокировка файла не является обязательным, и для открытых файлов разрешено удаление ссылок.

Но если я поставлю DeleteFile вне цикла блокировки, может произойти плохой сценарий

GC - CreateFile/LockFile/Unlock/CloseHandle,
write - oCreateFile/LockFile/WriteUpdatedData/Unlock/CloseHandle
GC - DeleteFile

У кого-нибудь есть идеи, как решить эту проблему? Есть ли какие-нибудь хитрости, которые позволяют совмещать блокировку файлов и удаление файлов или выполнять операции с атомарными файлами (Win32)?

Примечания:

  • Я не хочу использовать базу данных,
  • Я ищу решение для Win32 API для NT 5.01 и выше

Спасибо.

Ответы [ 3 ]

2 голосов
/ 19 декабря 2009

Я не очень понимаю, как это должно работать. Однако удаление файла, открытого другим процессом, возможно. Процесс, который создает файл, должен использовать флаг FILE_SHARE_DELETE для аргумента dwShareMode функции CreateFile (). Последующий вызов DeleteFile () будет успешным. Файл фактически не удаляется из файловой системы до тех пор, пока последний дескриптор на нем не будет закрыт.

1 голос
/ 19 декабря 2009

В настоящее время у вас есть данные в записи, которые позволяют ГХ определить, истекло ли время записи. Как насчет расширения этой служебной информации с помощью флага "TooLateWeAlreadyTimedItOut".

 GC sets TooLateWeAlreadyTimedItOut = true
 Release lock
    <== writer comes in here, sees the "TooLate" flag and so does not write
 GC deletes

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

Мне не ясно, что происходит в случае:

 GC checks timeout
 GC deletes
 Writer attempts write, and finds no file ...

Все, что вы запланировали для этого случая, также может быть использовано в случае "TooLate"

Отредактировано, чтобы добавить:

Вы сказали, что эта последовательность допустима:

 GC Deletes
 (Very slightly later) Writer attempts a write, sees no file, creates a new one

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

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

0 голосов
/ 19 декабря 2009

Для Windows вы можете использовать опцию FILE_FLAG_DELETE_ON_CLOSE для CreateFile - это приведет к удалению файла при закрытии дескриптора. Но я не уверен, что это удовлетворяет вашей семантике (потому что я не верю, что вы можете очистить атрибут delete-on-close.

Вот еще одна мысль. Как насчет переименования файла перед его удалением? Вы просто не можете закрыть окно ввода записи после того, как решили удалить файл, но что если вы переименуете файл перед его удалением? Затем, когда приходит запись, он увидит, что файл сеанса не существует, и создаст его заново.

Главное, что нужно иметь в виду, это то, что вы просто не можете закрыть рассматриваемое окно. ИМХО есть два решения:

  1. Добавление флага, подобного упомянутому djna или
  2. Требуется, чтобы для каждого сеанса с именем mutex был получен нежелательный побочный эффект сериализации записей в сеансе.

В чем недостаток наличия флага TooLate? Другими словами, что пойдет не так, если вы удалите файл преждевременно? Ведь ваша система должна иметь дело с отсутствующим файлом ...

...