快速调整mmap文件的大小

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

最简单的方法是在相同的文件上使用两个MAP_SHARED映射(增长文件,然后创建包含增长区域的第二个映射),然后在所有可以访问它的读取器完成后取消映射旧映射。 但是,我很好奇下面的方案是否可行,如果是的话,它是否有优势。

  • 使用MAP_PRIVATE映射文件
  • 在多个线程中对该内存执行只读访问
  • 要么获得文件的互斥锁,要写入内存(假设这是通过读取内存的读者不会被它搞砸的方式来完成的)
  • 或获取互斥锁,但增加文件的大小并使用mremap将其移动到新地址(调整映射的大小而不复制或不必要的文件IO。)
  • (4)中出现了疯狂的部分。 如果移动内存,则旧地址将变为无效,而仍在读取它的读者可能突然出现访问冲突。 如果我们修改读取器来捕获这个访问冲突,然后重新开始操作(即不重新读取错误的地址,重新计算给定偏移量的地址和mremap中的新基址)。是的,我知道这是邪恶的,但在我看来,读者只能成功读取旧地址处的数据,或者因访问冲突而重试失败。 如果足够小心,那应该是安全的。 由于重新调整大小不会经常发生,读者最终会成功,而不会陷入重试循环。

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

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

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


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

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

    如果您的文件太多以至于每个文件的最大映射超出地址空间,我的解决方案将无法工作,但这是64位地址空间的时代,因此希望您的最大映射大小不成问题。

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

    链接地址: http://www.djcxy.com/p/57123.html

    上一篇: Fast resize of a mmap file

    下一篇: How to display localized date and time information to web users with ASP.NET