澄清问题:
当OS发送命令将扇区写入磁盘时它是原子的吗?即,如果电源在写入命令之后立即失败,则新数据的写入将完全成功或旧数据保持不变.我不关心多扇区写入会发生什么 - 撕裂的页面是可以接受的.
老问题:
假设您在磁盘上有旧数据X,您在其上写入新数据Y,并且在写入期间树落在电源线上.如果没有花哨的UPS或备用电池的磁盘控制器,最终可能会出现页面撕裂的情况,磁盘上的数据是X部分和Y部分.您是否最终会遇到磁盘上的数据是X部分,Y部分的情况和部分垃圾?
我一直在努力理解像数据库这样的ACID系统的设计,而且我的天真想法似乎是firebird,它不使用预写日志,依赖于给定的写入不会破坏旧数据(X) - 只能完全写入新数据(Y).这意味着如果要覆盖X的一部分,则只能更改被覆盖的X部分,而不是我们打算保留的部分X.
为了澄清,这意味着如果你有一个页面大小的缓冲区,说4096个字节,充满了一半Y,一半X,我们要保持 - 我们告诉OS编写过X该缓冲区,有严重的磁盘的任何事都不短在写入期间我们想要保留的半X被破坏的失败.
如果我使用普通IO API读取和写入单个文件,则保证写入是基于每个块的原子.也就是说,如果我的write只修改了一个块,那么操作系统会保证写入整个块,或者根本不写入.
如何在内存映射文件上实现相同的效果?
内存映射文件只是字节数组,所以如果我修改字节数组,操作系统无法知道何时我认为写"完成",所以它可能(即使不太可能)在内存中交换内存我的块写操作的中间,实际上我写了半个块.
我需要某种形式的"进入/离开临界区",或"钉住"文件的页面到内存中,而我写它的一些方法.这样的事情存在吗?如果是这样,那可移植到常见的POSIX系统和Windows吗?
直接 I/O 是复制较大文件的最高效方法,因此我想将这种功能添加到程序中。
WindowsFILE_FLAG_WRITE_THROUGH在FILE_FLAG_NO_BUFFERINGWin32 的CreateFileA(). Linux 从 2.4.10 开始,为.open()
有没有办法在 POSIX 中实现相同的可移植结果?就像 Win32 API 从 Windows XP 到 Windows 11 的工作方式一样,如果能够以一种可靠的可移植方式跨所有类 UNIX 系统进行直接 IO,那就太好了。
我有一个生成大 SCSI 写入的用户空间应用程序(详细信息如下)。然而,当我查看到达 SCSI 目标(即存储,由 FC 连接)的 SCSI 命令时,某些东西将这些写入拆分为 512K 块。
该应用程序基本上会直接向设备进行 1M 大小的直接写入:
fd = open("/dev/sdab", ..|O_DIRECT);
write(fd, ..., 1024 * 1024);
Run Code Online (Sandbox Code Playgroud)
此代码导致发送两个 SCSI WRITE,每个 512K。
但是,如果我发出直接 SCSI 命令,而没有块层,则不会拆分写入。我从命令行发出以下命令:
sg_dd bs=1M count=1 blk_sgio=1 if=/dev/urandom of=/dev/sdab oflag=direct
Run Code Online (Sandbox Code Playgroud)
我可以看到一个 1M 大小的 SCSI WRITE。
问题是,什么是拆分写入,更重要的是,它是否可配置?Linux 块层似乎是有罪的(因为 SG_IO 不通过它)并且 512K 似乎太随意了,不能成为某种可配置的参数。
我正在编写一个在Linux和FreeBSD上运行的程序,我想确保每次write()返回时数据实际写入物理设备上的文件,这样我的数据就不会意外丢失(例如,电力丢失,过程意外中断等).
根据OPEN(2)手册页,在Linux(高于2.6)上,O_DIRECT是同步但可能有性能问题; 在FreeBSD上,O_DIRECT不能保证同步,也可能有问题.
所以,在Linux上,无论是O_DIRECT或O_SYNC保证同步写入,但哪一个具有更好的性能?
在FreeBSD上,为保证同步写入,哪个选项具有最佳性能:(1)O_DIRECT+ fsync()(2)O_DIRECT | O_SYNC或(3)O_SYNC单独?
这个15 年前的mmap 教程在 Google 搜索中排名很高,但实际上它在我的 Linux 系统上运行时出现了微妙的错误。
mmap_write.c:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#define FILEPATH "/tmp/mmapped.bin"
#define NUMINTS (1000)
#define FILESIZE (NUMINTS * sizeof(int))
int main(int argc, char *argv[])
{
int i;
int fd;
int result;
int *map; /* mmapped array of int's */
/* Open a file for writing.
* - Creating the file if it doesn't exist.
* - Truncating it to 0 size if it already …Run Code Online (Sandbox Code Playgroud)