内存映射实战之头文件定义
#ifndef QINIU_LARGEFILE_MMAPFILE_H_
#define QINIU_LARGEFILE_MMAPFILE_H_
#include <unistd.h>
#include <stdint.h>
namespace qiniu
{
namespace largefile
{
struct MMapOption
{
int32_t max_mmap_size_;
int32_t first_mmap_size_;
int32_t per_mmap_size_;
};
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(); /* 重新执行映射 */
private:
bool ensure_file_size(const int32_t size);
private:
int32_t size_;
int fd_;
void *data_;
struct MMapOption mmap_file_option_;
};
}
}
#endif /* */
内存映射实战之cpp源码实现
#include "mmap_file.h"
#include <stdio.h>
#include "common.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)
{
this->mmap_file_option_.max_mmap_size_ = mmap_option.max_mmap_size_;
this->mmap_file_option_.first_mmap_size_ = mmap_option.first_mmap_size_;
this->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;
}
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::remap_file() /* 重新执行映射 mremap */
{
/* 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;
}
bool MMapFile::ensure_file_size(const int32_t size)
{
struct stat s;
if (fstat(fd_, &s) < 0)
{
fprintf(stderr, "fstat error, error dest: %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::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;
}
}
}
}
内存映射实战-测试
#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 <errno.h>
#include <stdio.h>
#include <sys/mman.h>
#endif /* _COMMON_H_INCLUDED_ */
#include "common.h"
#include "mmap_file.h"
using namespace std;
using namespace qiniu;
static const mode_t OPEN_MODE = 0644; /* mode_t 是无符号整型 */
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成功返回 > 0 */
if (fd < 0)
{
return -errno; /* 出错errno返回正数 strerror(errno)别的程序员负负得正, 就可以调用这个函数获得错误的原因 */
}
return fd;
}
int main(void)
{
const char* filename = "./mapfile_test.txt";
/* 1. 打开创建一个文件, 取得文件的描述符 open 函数*/
int fd = open_file(filename, O_RDWR | O_CREAT | O_LARGEFILE);
if (fd < 0)
{
fprintf(stderr, "open file tailed 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");
}
close(fd);
return 0;
}
运行结果:
结语:
我以为, 上一学期的大一, 就直接到大二了, 学校居然要回校 2020-06-14 号回校, 好吧! 领导叫回只能会校, 大约 7月 xx 日就又回家.
感觉 大一 一下 子快到大二了, 还是赶紧加油学吧! 不然, 毕业就等于失业, 可就完蛋!
下节继续优化
希望, 给个赞反正你又不亏, 随便而已.
时间: 2020-06-19