【问题标题】:How to write data into an offset which is not 512*n bytes using linux native AIO?如何使用linux原生AIO将数据写入不是512 * n字节的偏移量?
【发布时间】:2019-05-23 01:29:35
【问题描述】:

我正在编写一些像 Bittorrent 客户端这样的应用程序来从网络下载文件并将其写入本地文件。我将获取部分数据并写入文件。

比如我要下载一个1GB的文件,我会得到offset 100, data: 312 bytesoffset 1000000, data: 12345offset 4000000, data: 888 bytes

我使用的是 Linux 原生 AIO(io_setup,io_submit,io_getevents),我发现了这个

使用linux内核AIO时,文件需要以O_DIRECT模式打开。这引入了对所有读写操作的进一步要求,以使其文件偏移、内存缓冲区和大小对齐到 512 字节。

那么我怎样才能将数据写入一些不是 512 对齐的偏移量?

例如,首先我将 4 个字节写入文件,所以我必须这样做:

fd = open("a.txt", O_CREAT | O_RDWR | O_DIRECT, 0666);
struct iocb cb;
char data[512] = "asdf";
cb.aio_buf = ALIGN(data, 512);
cb.aio_offset = 512;
cb.aio_nbytes = 512;

那我想在asdf后面追加数据:

struct iocb cb2;
char data2[512] = "ghij";
cb2.aio_buf = ALIGN(data2, 512);
cb2.aio_offset = 5;
cb2.aio_nbytes = 512;

写入会报错

Invalid argument (-22)

那该怎么做呢?

【问题讨论】:

  • 还要考虑预分配文件,这将有助于提高以后每次访问的性能。
  • 我怀疑你最好还是改用pwrite()pwritev()
  • @Shawn 谢谢,但我知道 pwrite 是块 I/O? posix AIO 更好吗?
  • how to download files using linux 这将告诉你如何使用WgetrTorrent 以及其他一些方法

标签: c linux aio


【解决方案1】:

如果您不使用O_DIRECT,您必须执行驱动程序会执行的操作。也就是说,读取整个块,更新您想要的部分,然后将其写回。块设备根本不允许较小的访问。

自己做会更有效率(例如,您可以更新同一块中的多个断开连接的序列,而只需一次读取和写入)。但是,由于您没有让驱动程序完成工作,因此您也无法在读-修改-写操作中获得任何原子性保证。

【讨论】:

  • 嗨,更新的问题。它不是读取文件并更新和写入。我正在从网上下载文件并将其写入本地文件。
  • @garen96:好的,这很容易。继续从网络读取,直到你有一个完整的块写入磁盘。即使是 512 字节的块对于批量文件传输来说也非常小,我会考虑一次节省大约 128kB。使用 torrent,您需要同时运行十几个缓冲区,但您也不会到处都有随机位。
  • 所以没有办法部分写?一旦数据满足要求(偏移量/大小为512对齐),我必须将数据缓存在内存中并写入文件?
  • @garen96:正确。是你在做,或者是 I/O 库和/或驱动在做,当你使用 O_DIRECT 时,你在做缓冲区管理
【解决方案2】:

你没有。 Linux AIO API 没有用处,尤其是对于您正在尝试做的事情。它是为了 Oracle 的缘故而添加的,Oracle 想要绕过内核的文件系统和块设备缓冲层以实现 Reasons™。它与 POSIX AIO 或其他合理的人谈论“AIO”时的意思没有任何关系。

【讨论】:

  • 我明白了...谢谢。也许我应该使用 POSIX AIO 来做非阻塞 IO?还是我应该只使用 pwrite?
  • 除非您要写入的存储空间会使您的任务在不间断的睡眠中冻结很长时间,否则请使用 pwrite。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-05-11
  • 1970-01-01
  • 2012-01-06
  • 2014-10-10
  • 1970-01-01
  • 1970-01-01
  • 2022-01-09
相关资源
最近更新 更多