【问题标题】:How do file-systems implement sector-locking?文件系统如何实现扇区锁定?
【发布时间】:2013-12-20 08:18:39
【问题描述】:

虽然这是一个一般性问题,但欢迎针对任何 Windows 或 Linux 或 Mac 支持的文件系统提供具体答案。

文件系统如何防止 2 个或更多进程同时读/写访问本地驱动器的扇区?

我知道显然需要采用某种类型的扇区锁定,但是...

  1. 这个操作系统范围的扇区锁的“类型”是什么:

    a) 命名互斥/命名信号量/文件映射? (在 Windows 上)

    b) 共享内存? (在 Linux 上)

  2. 这个扇区锁保存在哪里:在内存中?在磁盘上?无论哪种情况,无论此锁存储在何处,我都知道...

    a) 锁的存储必须是逻辑上的临时存储,因为如果它的所有者进程崩溃,锁不应永久或无限期地悬空。因此,如果这些锁存在于内存中会有所帮助。

    b) 锁的下落必须由所有进程通过名称或 ID 公开发现,该名称或 ID 找到了扇区号的函数。因此,如果进程 A 需要锁定扇区 S,A 应该知道如何首先访问扇区 S 的锁 L(S),如果 L(S) 尚不存在,则创建 L(S),尝试锁定 L(S),并且要么返回要么阻塞——所有这些都是原子的,因为另一个进程 B 也可能与 A 一起竞争,试图执行相同的步骤序列。

  3. 对于大型存储设备,扇区数也会很大。因此,显然不能在内存或磁盘上预先分配每个扇区的锁。

然而,我不知道或不理解的是,Linux 上的 ext* 文件系统、Windows 上的 FAT* 和 NTFS 以及 Mac 上的文件系统如何处理这个问题。

我的问题的实际上下文: 最终,我必须将上述答案应用于我正在使用 Java 7 NIO2 FileSystemProvider 编写的基于 Java 的自定义文件系统,其中 2 个或更多独立 Java 进程可能正在访问连接驱动器的一堆扇区以进行读/写。在 Java 7 中,我所知道的在进程之间实现共享内存的唯一非 JNI 方法是通过 MappedByteBuffer。但问题是,这个字节缓冲区将是“原始”内存——而我需要的是一个操作系统范围的互斥体类型机制,并且每个扇区 S 也可能每个互斥体。看来,我对这个 MappedByteBuffer 的更改除非我也调用MappedByteBuffer.force,否则不会在操作系统范围内以原子方式执行。

非常感谢所有答案和 cmets。

【问题讨论】:

  • 是什么让您认为文件系统实现了扇区锁定? “扇区锁定”到底是什么意思?
  • 如果扇区是一个共享资源,2个以上的进程可以同时读取/写入,那么这个资源,就像其他资源一样,在并发编程中需要序列化访问。这就是我所说的“扇区锁定”。但即使是你简短的反问题(你的措辞方式)也足以发人深省,所以没有冒犯,只是谢谢!
  • Harry,文件系统操作发生在驱动程序的内核模式下。驱动程序使用同步原语同步其线程,但不需要扇区锁定。
  • 感谢 Eugene,但是对于 Java 程序来说,内核驱动程序等价物是什么?大声地想知道,为什么 Java 的设计者没有考虑提供一个明确的“VM 驱动程序”工具,让所有 JVM 实例通用的代码都可以运行。
  • 在某些时候所有的 I/O 都变成了串行的。您似乎担心同时发生对同一扇区的两次写入。这不可能发生,因为硬件一次只能执行一项操作。所以问题是:我们如何防止多个进程同时访问同一个硬件?或者,它与一些“更高”级别的碰撞有关。并非所有文件系统都提供这种更高级别的预防。文件系统不需要防止下层冲突,就是驱动的问题。

标签: java filesystems locking shared-memory


【解决方案1】:

我认为您对现代文件系统的实现方式感到困惑,而旧系统通常不是多用户的;有了这个前言,让我们看一下称为journal 的东西。现在有一些替代方案 - 即

  1. Soft updates
  2. Log-structured file system
  3. Copy-on-write

然而,最常见的可能是日志文件系统。它写入空块并在写入完成时简单地移动指针(同时原子地写入“日志”),这允许在电源故障(或其他写入中断)的情况下“快速”恢复。

至于在系统级别锁定您的“日志”,我可能会像这样使用FileLock -

FileLock lock = null;
FileChannel channel = null;
try {
  // Get a file channel for the file
  File file = new File("journal");
  channel = new RandomAccessFile(file,
      "rw").getChannel();

  // Try acquiring the lock without blocking.
  try {
    lock = channel.tryLock();
    if (lock != null) {
      // GOT THE LOCK.... DO WORK...
      return true; // write success.
    }
  } catch (OverlappingFileLockException e) {
    // File is already locked in this thread or virtual
    // machine
  } finally {
    if (lock != null) {
      lock.release(); // Release the lock
    }
    if (channel != null) {
      channel.close(); // Close the file.
    }
  }
  return false; // Write must be retried?

【讨论】:

  • 我当然完全不了解情况,从未研究过文件系统的实现,甚至它们的内部设计。你和德韦恩给了我一些很棒的建议。非常感谢。 (我会等几天再将您的答案标记为最终答案。)
  • Elliot,我更倾向于实施期刊。但是,即使使用日志,我也需要防止 2 个或更多进程尝试同时附加到它。在 Java 领域,我如何获得一个操作系统范围的跨 JVM 互斥体来维护日志本身的完整性?
  • 你可以使用FileLock;这是tutorial
猜你喜欢
  • 2013-03-20
  • 2014-05-09
  • 1970-01-01
  • 2011-01-03
  • 2015-12-07
  • 1970-01-01
  • 1970-01-01
  • 2011-06-14
  • 1970-01-01
相关资源
最近更新 更多