当前位置: 代码迷 >> 综合 >> 《Operating systems:three easy pieces》:2.4 持续性
  详细解决方案

《Operating systems:three easy pieces》:2.4 持续性

热度:84   发布时间:2023-12-23 10:54:31.0

2.4 持续性

本书第三个重要的主题是可持续性(persistence)。在系统内存中,数据很容易丢失,因为DRAM等设备以易失性的(volatile)方式存储值,当停电或系统崩溃,在内存中的所有数据就丢失了。因此,我们需要硬件和软件能够持久的存储数据。这样的存储对于任何系统都是至关重要的,因为用户非常关心他们的数据。

硬件以某种输入/输出或I/O设备的形式出现;在现代系统中,硬盘是存储长期信息的常用存储库,尽管固态硬盘(SSDs)在这一领域也取得了很大进展。

在操作系统中,管理磁盘的软件通常被称为文件系统(file system)。它负责在系统的磁盘上以可靠和有效的方式存储用户创建的任何文件。

与操作系统为CPU和内存提供的抽象不同,操作系统不会为每个应用程序创建私有的虚拟化磁盘。相反,通常假设用户将会在文件之间共享文件信息。举个例子,在写C程序的时候,你可能会在编辑器里创建和编辑文件,编辑完成的时候,你希望通过编译器将源代码转化为可执行的代码,当编译完成的时候你希望运行这个程序。通过这个例子,你能看到这些文件在不同的进程之间是如何实现了文件共享。首先,编辑器创建了文件作为输入传递给编译器,编译器使用输入文件创建了新的可执行文件,最后可执行文件被运行。一个新的程序就这样诞生了。

为了更好地理解,我们来看一些代码。下列代码段演示了在/tmp目录下创建了包含字符串“hello world”的文件file,为实现这样一个需求,程序向操作系统做了三次调用。第一次,调用open()函数,打开文件(如果文件不存在则创建它);第二步,write(),向文件中写入数据;第三步,close(),关闭该文件,表明此程序将不再向该文件写入数据了。这些系统调用函数指向的是操作系统的文件系统部分,处理相关请求和返回某些错误代码给用户。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<assert.h>
#include<fcntl.h>
#include<sys/types.h>
int main(int argc,char *argv[])
{int fd = open("/tmp/file",O_WRONLY | O_CREAT | O_TRUNC,S_IRWXU);assert(fd > -1);/*文件描述符是非负整数,STDIN=0,标准输出是1,标准错误是2 */int rc = write(fd, "hello world\n",13);assert(rc == 13);close(fd);return 0;
}

你可能好奇操作系统为了实际写入磁盘做了些什么。在我们告诉你之前,请先闭上双眼。文件系统必须做一些工作:首先确定这些新数据在磁盘上的位置,然后在文件系统维护的各种结构中跟踪它。这样做需要向底层存储设备发出I/O请求,以读取现有结构或更新(写)它们。任何编写过设备驱动程序的人都知道,让设备为您做某事是一个复杂且细节的过程。它需要对底层设备接口及其确切的语义有深入的了解。幸运的是,OS提供了一种通过其系统调用访问设备的标准且简单的方法。因此,OS有时被视为标准库。

当然,设备是如何被访问的?文件系统如何在上述设备上持久地管理数据?在这里面有许多细节。出于性能原因,大多数文件系统会延迟写入一段时间,希望将它们批处理成一个较大的组。为了解决在写入时系统崩溃的问题,大多数文件系统都包含某种复杂的写协议,比如日志记录或写时复制,仔细地对磁盘上的写进行排序,以确保在写序列期间发生故障时,系统可以在事后恢复到合理的状态。为了使不同的公共操作更有效,文件系统使用许多不同的数据结构和访问方法,从简单的列表到复杂的B-Trees。如果这些都还不管用,好的。在这本关于持久性的书的第三部分中,我们将更详细地讨论所有这些内容,一般的设备和I/O,然后是磁盘、RAIDs和文件系统。