文件系统核心存储引擎_实现(一)

内存映射实战之头文件定义

在这里插入图片描述

#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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值