【问题标题】:What's going on (in the OS level) when I'm reading/writing a file?当我读/写文件时(在操作系统级别)发生了什么?
【发布时间】:2011-06-19 15:43:05
【问题描述】:

假设一个程序正在读取文件 F.txt,而另一个程序正在同时写入该文件。

(当我考虑如果我是系统程序员我将如何实现此功能时)我意识到可能存在歧义:

  1. 第一个程序会看到什么?

  2. 第二个程序在哪里写入新字节? (即“就地”写入与写入新文件,然后用新文件替换旧文件)

  3. 有多少程序可以同时写入同一个文件?

    .. 或许有些不那么明显。

所以,我的问题是:

  1. 读写文件功能的主要策略是什么?

  2. 它们在哪些操作系统(Windows、Linux、Mac OS 等)中受支持?

  3. 它可以依赖于某些编程语言吗? (我可以假设 Java 可以尝试在所有支持的操作系统上提供一些统一的行为)

【问题讨论】:

    标签: java file programming-languages filesystems operating-system


    【解决方案1】:

    单字节读取有很长的路要走,从磁板/闪存单元到您的本地 Java 变量。这是单个字节经过的路径:

    1. 磁板/闪速电池
    2. 内部硬盘缓冲区
    3. SATA/IDE 总线
    4. SATA/IDE 缓冲区
    5. PCI/PCI-X 总线
    6. 计算机的数据总线
    7. 计算机的 RAM 通过DMA
    8. 操作系统Page-cache
    9. Libc 读取缓冲区,也就是用户空间fopen() 读取缓冲区
    10. 本地 Java 变量

    出于性能原因,操作系统完成的大部分文件缓冲都保存在页面缓存中,将最近读取和写入的文件内容存储在 RAM 上。

    这意味着 Java 代码的每次读写操作都是在本地缓冲区中完成的:

    FileInputStream fis = new FileInputStream("/home/vz0/F.txt");
    
    // This byte comes from the user space buffer.
    int oneByte = fis.read();
    

    一个页面通常是一个 4KB 的内存块。每个页面都有一些特殊的标志和属性,其中之一是“脏页”,这意味着该页面有一些未写入物理媒体的修改数据。

    一段时间后,当操作系统决定将脏数据刷新回磁盘时,它会将数据发送到与原来相反的方向。

    每当两个不同的进程将数据写入同一个文件时,产生的行为是:

    • 不可能,如果文件被锁定。第二个进程将无法打开文件。
    • 未定义,如果写入文件的同一区域。
    • 预期,如果对文件的不同区域进行操作。

    “区域”取决于应用程序使用的内部缓冲区大小。例如,在一个 2 MB 的文件上,两个不同的进程可能会写入:

    • 前 1kB 数据中的一个 (0; 1024)。
    • 另一个关于最后 1kB 的数据(2096128;2097152)

    仅当本地缓冲区大小为 2 MB 时,才会发生缓冲区重叠和数据损坏。在 Java 上,您可以使用 Channel IO 来读取文件,并对里面发生的事情进行细粒度控制。

    许多事务性数据库通过发出sync operation 来强制将本地 RAM 缓冲区中的一些写入写回磁盘。与单个文件相关的所有数据都被刷新回磁板或闪存单元,有效地确保在断电时不会丢失任何数据。

    最后,memory mapped file 是一个内存区域,它允许用户进程直接从页面缓存读取和写入页面缓存,绕过用户空间缓冲。

    页面缓存系统对于protected mode 多任务操作系统的性能至关重要,每个现代操作系统(Windows NT 及以上、Linux、MacOS、*BSD)都支持所有这些功能。

    【讨论】:

      【解决方案2】:

      策略可以和文件系统一样多。通常,SO 侧重于通过在文件与光盘同步之前缓存文件来避免 I/O 操作。从缓冲区读取将看到以前保存的数据。所以在软硬件之间是一层缓冲(比如MySQL MyISAM引擎就用这个层很多)

      JVM 在关闭文件或程序调用 fsync() 之类的方法时将文件描述符缓冲区同步到磁盘,但是当缓冲区超过定义的阈值时,也可以通过 SO 同步。在 JVM 中,这当然是在所有支持的操作系统上统一的。

      【讨论】:

        【解决方案3】:
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-06-02
        • 2010-12-30
        • 1970-01-01
        • 2011-02-26
        • 2012-09-11
        • 2012-09-11
        • 1970-01-01
        相关资源
        最近更新 更多