1

请注意,这不是File r/w locking 和 unlink的重复。(区别-平台。文件的锁定和删除等操作具有完全不同的语义,因此结果会有所不同)。

我有以下问题。我想创建一个基于文件系统的会话存储,其中每个会话数据都存储在以会话 ID 命名的简单文件中。

我想要以下 API: write(sid,data,timeout), read(sid,data,timeout), remove(sid) where sid==file name, 另外我想要某种可以删除所有超时会话的 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)进行操作?

笔记:

  • 我不想使用数据库,
  • 我正在寻找适用于 NT 5.01 及更高版本的 Win32 API 的解决方案

谢谢。

4

3 回答 3

2

我真的不明白这应该如何工作。但是,可以删除由另一个进程打开的文件。创建文件的进程必须为 CreateFile() 的 dwShareMode 参数使用 FILE_SHARE_DELETE 标志。随后的 DeleteFile() 调用将成功。该文件实际上并没有从文件系统中删除,直到它的最后一个句柄关闭。

于 2009-12-19T16:41:01.167 回答
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 中增加一些额外的复杂性,但现在您不再依赖于任何特定于操作系统的皱纹。

我不清楚在这种情况下会发生什么:

 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 案例来说,这必须是正确的。

于 2009-12-19T14:25:48.177 回答
0

对于 Windows,您可以对 CreateFile 使用FILE_FLAG_DELETE_ON_CLOSE选项 - 这将导致在您关闭句柄时删除文件。但我不确定这是否满足您的语义(因为我不相信您可以清除 delete-on-close 属性。

这是另一个想法。在删除文件之前重命名文件怎么样?在您决定删除文件后,您根本无法关闭写入的窗口,但是如果您在删除文件之前重命名文件怎么办?然后当写入进来时,它会看到会话文件不存在并重新创建它。

要记住的关键是您根本无法关闭有问题的窗口。恕我直言,有两种解决方案:

  1. 添加一个像 djna 提到的标志或
  2. 要求获取一个名为 mutex 的每个会话,它具有在会话上序列化写入的不幸副作用。

拥有 TooLate 标志的缺点是什么?换句话说,如果您过早地删除文件会出现什么问题?毕竟你的系统必须处理不存在的文件......

于 2009-12-19T15:59:08.210 回答