文章目錄
1 文件映射操作類的實現
mmap_file_op.h:
#ifndef QINIU_LARGEFILE_MMAPFILE_OP_H_
#define QINIU_LARGEFILE_MMAPFILE_OP_H_
#include "common.h"
#include "file_op.h"
#include "mmap_file.h"
namespace qiniu
{
namespace largefile
{
class MMapFileOperation: public FileOperation
{
public:
MMapFileOperation(const std::string& file_name, const int open_flags = O_CREAT | O_RDWR | O_LARGEFILE):
FileOperation(file_name, open_flags), map_file_(NULL), is_mapped_(false)
{
}
~MMapFileOperation()
{
if(map_file_){
delete(map_file_);
map_file_ = NULL;
}
}
int mmap_file(const MMapOption& mmap_option);
int munmap_file();
int pread_file(char *buf, const int32_t size, const int64_t offset);
int pwrite_file(const char* buf, const int32_t sized, const int64_t offset);
void *get_map_data() const ;
int flush_file();
private:
MMapFile *map_file_;
bool is_mapped_;
};
}
}
#endif //QINIU_LARGEFILE_MMAPFILE_OP_H_
mmap_file_op.cpp:
#include "mmap_file_op.h"
#include "common.h"
//#include "file_op.h"
//#include "mmap_file.h"
static int debug = 1;
namespace qiniu
{
namespace largefile
{
int MMapFileOperation::mmap_file(const MMapOption& mmap_option)
{
if(mmap_option.max_mmap_size_ < mmap_option.first_mmap_size_)
{
return TFS_ERROR;
}
if(mmap_option.max_mmap_size_ <= 0){
return TFS_ERROR;
}
int fd = check_file();
if(fd < 0){
fprintf(stderr, "MMapFileOperation::mmap_file - checking file failed!");
return TFS_ERROR;
}
if(!is_mapped_)
{
if(map_file_)
{
delete(map_file_);
}
map_file_ = new MMapFile(mmap_option, fd);
is_mapped_ = map_file_->map_file(true);
}
if(is_mapped_)
{
return TFS_SUCCESS;
}
else
{
return TFS_ERROR;
}
}
int MMapFileOperation::munmap_file()
{
if(is_mapped_ && map_file_ != NULL)
{
delete(map_file_);
is_mapped_ = false;
}
return TFS_SUCCESS;
}
void *MMapFileOperation::get_map_data() const
{
if(is_mapped_){
return map_file_->get_data();
}
return NULL;
}
int MMapFileOperation::pread_file(char *buf, const int32_t size, const int64_t offset)
{
//情況1,內存已經映射
if(is_mapped_ && (offset + size) >map_file_->get_size())
{
if(debug) fprintf(stdout, "MMapFileOperation: pread,size: %d, offset: %" __PRI64_PREFIX "d,map file size: %d. need remap\n",
size, offset, map_file_->get_size());
map_file_->remap_file();
}
if(is_mapped_ && (offset + size) <=map_file_->get_size())
{
memcpy(buf, (char *)map_file_->get_data() +offset, size);
return TFS_SUCCESS;
}
//情況2,內存沒有映射或是要讀取的數據映射不全
return FileOperation::pread_file(buf, size, offset);
}
int MMapFileOperation::pwrite_file(const char* buf, const int32_t size, const int64_t offset)
{
//情況1,內存已經映射
if(is_mapped_ && (offset + size) >map_file_->get_size())
{
if(debug) fprintf(stdout, "MMapFileOperation: pwrite,size: %d, offset: %" __PRI64_PREFIX "d,map file size: %d. need remap\n",
size, offset, map_file_->get_size());
map_file_->remap_file();
}
if(is_mapped_ && (offset + size) <=map_file_->get_size())
{
memcpy((char *)map_file_->get_data() +offset, buf, size);
return TFS_SUCCESS;
}
//情況2,內存沒有映射或是要寫入的數據映射不全
return FileOperation::pwrite_file(buf, size, offset);
}
int MMapFileOperation::flush_file()
{
if(is_mapped_)
{
if(map_file_->sync_file()){
return TFS_SUCCESS;
}
else
{
return TFS_ERROR;
}
}
return FileOperation::flush_file();
}
}
}
test.cpp:
#include "mmap_file_op.h"
#include <iostream>
using namespace std;
using namespace qiniu;
const static largefile::MMapOption mmap_option={10240000, 4096, 4096}; //內存映射的參數
int main(void)
{
int ret = 0;
const char * filename = "mmap_file_op.txt";
largefile::MMapFileOperation *mmfo = new largefile::MMapFileOperation(filename);
int fd = mmfo->open_file();
if(fd < 0){
fprintf(stderr, "open file %s failed. reason: %s\n", filename, strerror(-fd));
exit(-1);
}
ret = mmfo->mmap_file(mmap_option);
if(ret == largefile::TFS_ERROR)
{
fprintf(stderr, "mmap_file failed. reason: %s\n", strerror(errno));
mmfo->close_file();
exit(-2);
}
char buffer[128+1];
memset(buffer, '6', 128);
buffer[127]='\n';
ret = mmfo->pwrite_file(buffer, 128, 8);
if(ret < 0){
if(ret == largefile::EXIT_DISK_OPER_INCOMPLETE){
fprintf(stderr, " pwrite_file: read length is less than required!\n");
}else {
fprintf(stderr, "pwrite file %s failed. reason: %s\n", filename, strerror(-ret));
}
}
memset(buffer, 0, 128);
ret = mmfo->pread_file(buffer, 128, 8);
if(ret < 0){
if(ret == largefile::EXIT_DISK_OPER_INCOMPLETE){
fprintf(stderr, " pread_file: read length is less than required!");
}else {
fprintf(stderr, "pread file %s failed. reason: %s\n", filename, strerror(-ret));
}
}else {
buffer[128] = '\0';
printf("read: %s\n", buffer);
}
ret = mmfo->flush_file();
if(ret == largefile::TFS_ERROR)
{
fprintf(stderr, "flush file failed. reason: %s\n", strerror(errno));
}
memset(buffer, '8', 128);
buffer[127]='\n';
ret = mmfo->pwrite_file(buffer, 128, 4000); // 即使這裏的偏移量很大,也會自動擴充文件的
mmfo->munmap_file();
mmfo->close_file();
return 0;
}
參考資料: