2009-12-19 2 views
1

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

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

Я хочу следующего API: write(sid,data,timeout), read(sid,data,timeout), remove(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 на opended заблокированный файл (в отличие от Unix, где файл блокировки не является обязательным и UNLINK допускается для открытых файлов.

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

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

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

Примечания:

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

Спасибо.

+1

Наверное, это выглядит как обман. Пожалуйста, объясните различия, или это может быть закрыто. – 2009-12-19 14:07:39

+0

Добавлено explenation - POSIX и Win32 требовали совершенно разных решений – Artyom

ответ

2

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

+0

Хорошо, я вижу, мне совсем не нужно LockFile. Если я укажу 'CreateFile (« file.txt », ..., FILE_SHARE_DELETE, ...)' без 'FILE_SHARE_READ | FILE_SHARE_WRITE' только один поток/процесс мог бы держать файл открытым. Я прав? Так что мне вообще не нужно блокировать, правда? – Artyom

+0

На самом деле это похоже на то, что Windows слишком отличается от Unix: Win32: CreateFile (ok), DeleteFile (ok), CreateFile (fail). Unix: open (ok), unlink (ok), open (ok - другой файл). Это меня смутило. – Artyom

1

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

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

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

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

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 

ВИР ter может обрабатывать флаг tooLate как идентичный этому случаю.Он просто создает файл с другим именем, используя номер версии в качестве задней части его имени. Открытие файла сеанса в первый раз требует поиска в каталоге, но затем вы можете записать последнее имя в сеансе.

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

+0

Проблема, которую я хочу, чтобы писатель «отключил» TooLate, что означает обновление файла. Поэтому решение, которое вы предлагаете мне, недействительно. Второй пункт (писатель пытается записать, тогда он должен создать файл) – Artyom

+0

Вам не нужно отключать tooLate, вы можете изменить порядок операций. Я отредактирую, чтобы объяснить. – djna

0

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

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

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

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

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

Смежные вопросы