快速调整mmap文件的大小

我需要一个非常大的mmap文件的无副本重新大小,同时仍然允许并发访问读者线程。

简单的方法是使用两个MAP_SHARED映射(增长文件,然后创build第二个映射,其中包括增长的区域)在相同的进程在同一个文件,然后取消映射旧的映射一旦所有的读者可以访问它完成。 不过,我很好奇下面的scheme能否奏效,如果有的话,是否有利呢?

  1. 使用MAP_PRIVATE映射文件
  2. 在多个线程中对这个内存进行只读访问
  3. 要么获取文件的互斥量,要写入内存(假设这是通过读取内存的读者不会被搞乱的方式来完成的)
  4. 或获取互斥锁,但增加文件的大小,并使用mremap将其移动到一个新的地址(调整映射的大小,而不复制或不必要的文件IO)。

(4)中的疯狂部分。 如果移动内存,则旧地址变得无效,而仍在读取它的读者可能突然出现访问冲突。 如果我们修改读取器来捕获这个访问冲突,然后重新开始操作(即不重新读取错误的地址,重新计算给定偏移量的地址和mremap的新的基地址)。是的,我知道这是邪恶的,但在我看来,读者只能成功读取旧地址的数据,或者在访问冲突后重试失败。 如果足够小心,那应该是安全的。 由于resize不会经常发生,读者最终会成功,而不会陷入重试循环。

如果旧的地址空间被重新使用,而读者仍然有一个指向它的指针,则可能会发生问题。 那么就没有访问违规,但数据不正确,程序进入了未定义行为的独angular兽和糖果填补的土地(其中通常不是独angular兽和糖果)。

但是,如果完全控制了分配,并且可以确保在此期间发生的任何分配都不会重复使用这个旧的地址空间,那么这应该不成问题,行为也不应该是未定义的。

我对吗? 这可以工作吗? 使用两个MAP_SHARED映射有没有什么好处?

Solutions Collecting From Web of "快速调整mmap文件的大小"

我很难想象一个你不知道文件有多大的上限的情况。 假设这是真的,当文件首先映射到mmap()时,可以通过提供该大小来“保留”文件的最大大小的地址空间。 当然,超出文件实际大小的任何访问都会导致访问冲突,但这就是您希望它能够正常工作的原因 – 您可能会争辩说,保留额外的地址空间可确保访问冲突,而不是将该地址范围保留为开放状态被其他调用用于像mmap()或malloc()。

无论如何,重点是我的解决方案,你永远不会移动的地址范围,你只能改变它的大小,现在你的锁定是围绕数据结构,为每个线程提供当前有效的大小。

我的解决方案不工作,如果你有太多的文件,每个文件的最大映射运行你的地址空间,但这是64位地址空间的时代,所以希望你的最大映射的大小是没有问题的。

(为了确保我没有忘记一些愚蠢的事情,我写了一个小程序来说服自己创建大于文件大小的映射,当您尝试访问超出文件大小时会导致访问冲突,然后工作正常一旦你ftruncate()文件变大,所有的第一个mmap()调用返回相同的地址。