繁体   English   中英

快速调整mmap文件的大小

[英]Fast resize of a mmap file

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

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

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

疯狂的部分出现在(4)。 如果移动内存,旧地址将变为无效,仍在阅读内容的读者可能会突然发生访问冲突。 如果我们修改读取器以捕获此访问冲突然后重新启动操作(即不重新读取错误地址,重新计算给定偏移量的地址和mremap中的新基址),该怎么办。是的我知道这是邪恶的但是在我看来,读者只能成功读取旧地址的数据,或者因访问冲突而失败并重试。 如果采取足够的谨慎措施,那应该是安全的。 由于重新调整大小不会经常发生,读者最终会成功并且不会陷入重试循环。

如果在读取器仍具有指向它的指针时重新使用旧地址空间,则可能会出现问题。 然后将没有访问冲突,但数据将是不正确的,并且程序进入不确定行为的独角兽和糖果填充的土地(其中通常既没有独角兽也没有糖果。)

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

我对吗? 这可行吗? 使用两个MAP_SHARED映射是否有任何优势?

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

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

如果您有这么多文件,每个文件的最大映射会使您超出地址空间,我的解决方案不起作用,但这是64位地址空间的年龄,所以希望您的最大映射大小没有问题。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM