欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 运维知识 > windows >内容正文

windows

淘宝文件系统文件映射原理及实现

发布时间:2025/4/5 windows 37 豆豆
生活随笔 收集整理的这篇文章主要介绍了 淘宝文件系统文件映射原理及实现 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

文章目录

    • 1 文件系统映射原理
      • 1.1 文件映射应用场景
      • 1.2 文件映射相关函数介绍
    • 2 文件映射实战

1 文件系统映射原理

1.1 文件映射应用场景

主要应用场景如下:

  • 进程间共享信息。
  • 实现文件数据从磁盘到内存的映射,极大的提升应用程序访问文件的速度。

1.2 文件映射相关函数介绍

作用:将一个文件或者其它对象映射进内存。

  • 使用普通文件提供的内存映射。
  • 使用特殊文件提供匿名内存映射。

  • mmap函数:

    #include <sys/mman.h>void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);int munmap(void *addr, size_t length); /* 参数start:指向欲映射的内存起始地址,通常设为 NULL,代表让系统自动选定地址,映射成功后返回该地址。参数length:代表将文件中多大的部分映射到内存。参数prot:映射区域的保护方式。可以为以下几种方式的组合:PROT_EXEC 执行 PROT_READ 读取 PROT_WRITE 写入 PROT_NONE 不能存取参数flags:影响映射区域的各种特性。必须要指定MAP_SHARED 或MAP_PRIVATE。MAP_SHARED - 映射区域数据与文件对应,允许其他进程共享MAP_PRIVATE - 映射区域生成文件的copy,修改不同步文件MAP_ANONYMOUS - 建立匿名映射。此时会忽略参数fd,不涉及文件,而且映射区域无法和其他进程共享。MAP_DENYWRITE - 允许对映射区域的写入操作,其他对文件直接写入的操作将会被拒绝。MAP_LOCKED - 将映射区域锁定住,这表示该区域不会被置swap参数fd:要映射到内存中的文件描述符。如果使用匿名内存映射时,即flags中设置了MAP_ANONYMOUS,fd设为-1。有些系统不支持匿名内存映射,则可以使用fopen打开/dev/zero文件,然后对该文件进行映射,可以同样达到匿名内存映射的效果。参数offset:文件映射的偏移量,通常设置为0,代表从文件最前方开始对应,offset必须是分页大小的整数倍(分页大小一般是4KB)。  */

    msync函数介绍:
    实现磁盘文件内容于共享内存区中的内容一致,即同步操作。

    //函数原型 int msync ( void * addr, size_t len, int flags) //头文件 #include<sys/mman.h> /* addr:文件映射到进程空间的地址; len:映射空间的大小; flags:刷新的参数设置,可以取值MS_ASYNC/ MS_SYNC 其中:取值为MS_ASYNC(异步)时,调用会立即返回,不等到更新的完成;取值为MS_SYNC(同步)时,调用会等到更新完成之后返回;返回值:成功则返回0;失败则返回-1; */

    mremap函数介绍:
    扩大(或缩小)现有的内存映射。

    //函数原型 void * mremap(void *old_address, size_t old_size , size_t new_size, int flags);//头文件 #include <unistd.h> #include <sys/mman.h>/* addr: 上一次已映射到进程空间的地址; old_size: 旧空间的大小; new_size: 重新映射指定的新空间大小; flags: 取值可以是0或者MREMAP_MAYMOVE,0代表不允许内核移动映射区域,MREMAP_MAYMOVE则表示内核可以根据实际情况移动映射区域以找到一个符合new_size大小要求的内存区域返回值:成功则返回映射后内存区域的地址,失败则返回(void*)-1; */

    2 文件映射实战

    主要由map_file.cpp、map_file.h、common.h、main.cpp几个文件。

    common.h:

    #ifndef _COMMON_H_INCLUDED_ #define _COMMON_H_INCLUDED_#include <iostream> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> #include <string> #include <string.h> #include <stdint.h> #include <inttypes.h> #include <errno.h> #include <stdio.h> #include <sys/mman.h> #include <unistd.h> #include <stdlib.h> #include <assert.h>#endif /*_COMMON_H_INCLUDED_*/

    map_file.h:

    #ifndef QINIU_LARGEFILE_MMAPFILE_H_ #define QINIU_LARGEFILE_MMAPFILE_H_#include <unistd.h> #include "common.h"namespace qiniu {namespace largefile{class MMapFile{public:MMapFile();explicit MMapFile(const int fd);MMapFile(const MMapOption& mmap_option, const int fd);~MMapFile();bool sync_file(); //同步内存数据到文件bool map_file(const bool write = false); //将文件映射到内存,同时设置访问权限void *get_data() const ; //获取映射到内存数据的首地址int32_t get_size() const; //获取映射数据的大小bool munmap_file(); //解除映射bool remap_file(); //重新执行映射 mremapprivate:bool ensure_file_size(const int32_t size);private:int32_t size_;int fd_;void *data_;struct MMapOption mmap_file_option_; };}}#endif //

    map_file.cpp:

    #include "mmap_file.h" #include <stdio.h>static int debug = 1;namespace qiniu {namespace largefile{MMapFile::MMapFile():size_(0), fd_(-1), data_(NULL){}MMapFile::MMapFile(const int fd):size_(0), fd_(fd), data_(NULL){}MMapFile::MMapFile(const MMapOption& mmap_option, const int fd):size_(0), fd_(fd), data_(NULL){mmap_file_option_.max_mmap_size_ = mmap_option.max_mmap_size_;mmap_file_option_.first_mmap_size_ = mmap_option.first_mmap_size_;mmap_file_option_.per_mmap_size_ = mmap_option.per_mmap_size_;}MMapFile::~MMapFile(){if(data_){if(debug) printf("mmap file destruct, fd: %d, maped size: %d, data: %p\n", fd_, size_, data_);msync(data_, size_, MS_SYNC);munmap(data_, size_);size_ = 0;data_ = NULL;fd_ = -1;mmap_file_option_.max_mmap_size_ = 0;mmap_file_option_.first_mmap_size_ = 0;mmap_file_option_.per_mmap_size_ = 0;}}bool MMapFile::sync_file(){if(NULL !=data_ && size_ > 0){return msync(data_, size_, MS_ASYNC)==0;}return true;}bool MMapFile::map_file(const bool write ){int flags = PROT_READ;if(write){flags |= PROT_WRITE;}if(fd_<0){return false;}if(0 == mmap_file_option_.max_mmap_size_){return false;}if(size_<mmap_file_option_.max_mmap_size_){size_ = mmap_file_option_.first_mmap_size_;}else {size_ = mmap_file_option_.max_mmap_size_;}if(!ensure_file_size(size_)){fprintf(stderr, "ensure file size failed in map_file , size : %d\n", size_);return false; }data_ = mmap(0, size_, flags, MAP_SHARED, fd_, 0);if(MAP_FAILED == data_){fprintf(stderr, "map file failed: %s\n", strerror(errno));size_ = 0;fd_ = -1;data_ = NULL;return false;}if(debug) printf("mmap file successed, fd: %d maped size: %d, data: %p\n", fd_, size_, data_);return true;}void *MMapFile::get_data() const {return data_;}int32_t MMapFile::get_size() const{return size_;}bool MMapFile::munmap_file(){if(munmap(data_, size_)==0){return true;}else {return false;}}bool MMapFile::ensure_file_size(const int32_t size){struct stat s;if(fstat(fd_, &s) < 0){fprintf(stderr, "fstat error, error desc: %s\n", strerror(errno));return false;}if(s.st_size < size){if(ftruncate(fd_, size) < 0){fprintf(stderr, "ftruncate error, size: %d, error desc: %s\n", size, strerror(errno));return false;}}return true; }bool MMapFile::remap_file(){//1. 防御性编程if(fd_ < 0 || data_ == NULL){fprintf(stderr, "mremap not mapped yet\n");return false;}if(size_ == mmap_file_option_.max_mmap_size_){fprintf(stderr, "already mapped max size, now size: %d, max size: %d\n", size_, mmap_file_option_.max_mmap_size_);return false;}int32_t new_size = size_+ mmap_file_option_.per_mmap_size_;if(new_size > mmap_file_option_.max_mmap_size_){new_size = mmap_file_option_.max_mmap_size_;}if(!ensure_file_size(new_size)){fprintf(stderr, "ensure file size failed in remap_file , size : %d\n", new_size);return false; }if(debug) printf("mremap start. fd: %d, now size: %d, new size: %d, old data: %p\n", fd_, size_, new_size, data_);void *new_map_data = mremap(data_, size_, new_size, MREMAP_MAYMOVE);if(MAP_FAILED == new_map_data){fprintf(stderr, "mremap failed , fd: %d, new size: %d, error desc: %s\n", fd_, new_size, strerror(errno));return false;}else {if(debug) printf("mremap success. fd: %d, now size: %d, new size: %d, old data: %p, new data: %p\n", fd_, size_, new_size,data_, new_map_data);}data_ = new_map_data;size_ = new_size;return true;}} }

    main.cpp:

    #include "mmap_file.h" #include "common.h"using namespace std; using namespace qiniu;static const mode_t OPEN_MODE = 0644; const static largefile::MMapOption mmap_option={10240000, 4096, 4096}; //内存映射的参数int open_file(string file_name, int open_flags){int fd = open(file_name.c_str(), open_flags, OPEN_MODE); //open 成功返回的一定是>0if(fd < 0){return -errno; //errno strerror(errno); //read errno}return fd;}int main(void ){const char *filename = "./mapfile_test.txt";//1. 打开/创建一个文件,取得文件的句柄 open函数int fd = open_file(filename, O_RDWR | O_LARGEFILE);if(fd<0){//调用read ,出错重置 errno fprintf(stderr, "open file failed. filename:%s, error desc: %s\n", filename, strerror(-fd));return -1;}largefile::MMapFile *map_file = new largefile::MMapFile(mmap_option, fd);bool is_mapped = map_file->map_file(true);if(is_mapped){map_file->remap_file();memset(map_file->get_data(), '9', map_file->get_size());map_file->sync_file();map_file->munmap_file();}else {fprintf(stderr, "map file failed\n");}delete map_file;close(fd);return 0; }

    参考资料:

  • C/C++从入门到精通-高级程序员之路【奇牛学院】
  • 总结

    以上是生活随笔为你收集整理的淘宝文件系统文件映射原理及实现的全部内容,希望文章能够帮你解决所遇到的问题。

    如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。