【问题标题】:appending to a memory-mapped file附加到内存映射文件
【发布时间】:2011-05-26 12:29:54
【问题描述】:

我不断地附加到股票报价文件(整数、多头、双精度等)。我用 mmap 将此文件映射到内存中。

使新附加的数据作为内存映射的一部分可用的最有效方法是什么?

我知道我可以再次打开文件(新文件描述符),然后对其进行 mmap 以获取新数据,但这似乎效率低下。向我建议的另一种方法是将文件预分配为 1mb 块,写入特定位置直到结束,然后将文件 ftruncate 到 +1mb。

还有其他方法吗?

Boost 对此有帮助吗?

【问题讨论】:

    标签: c++ boost mmap


    【解决方案1】:

    man page for mremap应该是可以的。

    【讨论】:

    • mremap 是特定于 Linux 的。
    【解决方案2】:

    Boost.IOStreams 仅具有固定大小的memory mapped files,因此对您的具体问题没有帮助。 Linux 有一个接口mremap,其工作原理如下:

    void *new_mapping = mremap(mapping, size, size + GROWTH, MREMAP_MAYMOVE);
    if (new_mapping == MAP_FAILED)
        // handle error
    mapping = new_mapping;
    

    但是,这是不可移植的(并且文档记录不充分)。 Mac OS X 好像没有mremap

    无论如何,您都不需要重新打开文件,只需munmapmmap 再次:

    void *append(int fd, char const *data, size_t nbytes, void *map, size_t &len)
    {
        // TODO: check for errors here!
        ssize_t written = write(fd, data, nbytes);
        munmap(map, len);
        len += written;
        return mmap(NULL, len, PROT_READ, 0, fd, 0);
    }
    

    预分配方案在这里可能非常有用。请务必跟踪文件的实际长度并在关闭前再次截断它。

    【讨论】:

      【解决方案3】:

      我知道答案已被接受,但如果我提供我的答案,也许它会对其他人有所帮助。提前分配一个大文件,比如 10 GiB 大小。提前创建其中三个文件,我称它们为卷。跟踪您最后一个已知位置,例如在标题、另一个文件等中,然后从该点继续追加。如果您达到文件的最大大小并且空间不足,请切换到下一卷。如果没有更多卷,请创建另一个卷。请注意,您可能会提前几个卷执行此操作,以确保不会阻塞等待创建新卷的追加。这就是我们在 DVR 系统中存储连续传入的视频/音频以进行监控的工作方式。我们不会浪费空间来存储视频剪辑的文件名,这就是为什么我们不使用真正的文件系统,而是使用平面文件,我们只跟踪偏移量、帧信息(fps、帧类型、宽度/高度等) )、时间记录和摄像机频道。对你来说,存储空间对于你正在做的工作来说很便宜,而你的时间是无价的。所以,尽可能多地抓住你想要的时间。您基本上是在实施针对您的需求优化的自己的文件系统。通用文件系统提供的需求与我们在其他领域的需求不同。

      【讨论】:

        【解决方案4】:

        我的 5cents,但它们更特定于 C。 制作普通文件,但 mmap 很大 - 例如文件说 100K,但 mmap 1GB 或更多。然后,您可以安全地访问文件大小的所有内容。访问超过文件大小将导致错误。 如果您使用的是 32 位操作系统,请不要让 mmap 太大,因为它会占用您的地址空间。

        【讨论】:

          【解决方案5】:

          如果您在 Windows 上使用 boost/iostreams/device/mapped_file.hpp

          boost::filesystem::resize_file 如果由于缺少共享权限而打开读取映射对象,则会引发异常。 而是使用windows-api调整光盘上的文件大小,读取mapped_files还是可以打开的。

          bool resize_file_wapi(string path, __int64 new_file_size) //boost::uintmax_t size
          {
              HANDLE handle = CreateFile(path.c_str(), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING,
              FILE_ATTRIBUTE_NORMAL, 0);
              LARGE_INTEGER sz;
              sz.QuadPart = new_file_size;
          
              return handle != INVALID_HANDLE_VALUE
              && ::SetFilePointerEx(handle, sz, 0, FILE_BEGIN)
              && ::SetEndOfFile(handle)
              && ::CloseHandle(handle);
          }
          

          【讨论】:

            猜你喜欢
            • 2010-12-28
            • 1970-01-01
            • 2016-02-23
            • 1970-01-01
            • 2018-05-18
            • 1970-01-01
            • 1970-01-01
            • 2010-11-01
            相关资源
            最近更新 更多