当前位置: 首页 > article >正文

Rucbase 存储管理——磁盘管理器

1.需求

本题需要实现磁盘管理器DiskManager的相关接口,磁盘管理器负责文件操作、读写页面等。阅读项目结构文档中磁盘管理器的相关说明,以及代码框架中src/errors.h、src/storage/disk_manager.h、src/storage/disk_manager.cpp、src/common/config.h文件,

实现以下接口:

(1)void DiskManager::create_file(const std::string &path);

该接口的参数path为文件名,该接口的功能是创建文件,其文件名为path参数指定的文件名。

(2)void DiskManager::open_file(const std::string &path);

该接口的参数path为文件名,该接口的功能是打开文件名参数path指定的文件。

(3)void DiskManager::close_file(const std::string &path);

该接口的参数path为文件名,该接口的功能是关闭文件名参数path指定的文件。

(4)void DiskManager::destroy_file(const std::string &path);

该接口的参数path为文件名,该接口的功能是删除文件名参数path指定的文件。

(5)void DiskManager::write_page(int fd, page_id_t page_no, const char *offset, int num_bytes);

该接口负责在文件的指定页面写入指定长度的数据,该接口从指定页面的起始位置开始写入数据。

(6)void DiskManager::read_page(int fd, page_id_t page_no, char *offset, int num_bytes);

该接口需要从文件的指定页面读取指定长度的数据,该接口从指定页面的起始位置开始读取数据。

2.熟悉框架

查看disk_manager数据结构,path2fd_与fd2path_两张哈希表用来相互映射文件句柄和文件路径,保证在O(1)的时间复杂度内查询,两张表的功能为:查看记录文件是否被打开,存在于两张表的文件即为正在被打开的文件

   private:
    // 文件打开列表,用于记录文件是否被打开
    std::unordered_map<std::string, int> path2fd_;  //<Page文件磁盘路径,Page fd>哈希表
    std::unordered_map<int, std::string> fd2path_;  //<Page fd,Page文件磁盘路径>哈希表

    int log_fd_ = -1;                             // WAL日志文件的文件句柄,默认为-1,代表未打开日志文件
    std::atomic<page_id_t> fd2pageno_[MAX_FD]{};  // 文件中已经分配的页面个数,初始值为0

接着看另外一个重要的函数is_file

此函数的作用是通过文件路径判断该文件是否存在数据库中,不在及时抛出异常,防止异常访问导致段错误崩溃

/**
 * @description: 判断指定路径文件是否存在
 * @return {bool} 若指定路径文件存在则返回true 
 * @param {string} &path 指定路径文件
 */
bool DiskManager::is_file(const std::string &path) {
    // 用struct stat获取文件信息
    struct stat st;
    return stat(path.c_str(), &st) == 0 && S_ISREG(st.st_mode);
}

所有的修改均在rucbase-lab/src/storage/disk_manager.cpp

3.实现功能

create_file(const std::string &path)

  • O_RDWR 是一个打开模式标志,表示以可读写的方式打开文件。
  • O_CREAT 是一个创建标志,表示如果文件不存在,则创建一个新文件。
  • S_IRUSR | S_IWUSR 是权限标志,表示用户具有读取和写入权限。

1.打开文件时既具有读写权限又能够创建文件

2.用户具有读取和写入权限

/**
 * @description: 用于创建指定路径文件
 * @return {*}
 * @param {string} &path
 */
void DiskManager::create_file(const std::string &path) {
    // Todo:
    // 调用open()函数,使用O_CREAT模式
    // 注意不能重复创建相同文件
    if(is_file(path)) {throw FileExistsError(path);}//通过is_file函数保证不创建重复的文件
    int fd = open(path.c_str(),O_RDWR | O_CREAT , S_IRUSR | S_IWUSR );
    if( fd < 0) throw FileNotOpenError(fd);
    close(fd);
}

destroy_file(const std::string &path)

/**
 * @description: 删除指定路径的文件
 * @param {string} &path 文件所在路径
 */
void DiskManager::destroy_file(const std::string &path) {
    // Todo:
    // 调用unlink()函数
    // 注意不能删除未关闭的文件
    if(!is_file(path)) throw FileNotFoundError(path);
    if(path2fd_.count(path)) throw FileNotClosedError(path);//文件未关闭
    unlink(path.c_str());
}

 open_file(const std::string &path)

/**
 * @description: 打开指定路径文件 
 * @return {int} 返回打开的文件的文件句柄
 * @param {string} &path 文件所在路径
 */
int DiskManager::open_file(const std::string &path) {
    // Todo:
    // 调用open()函数,使用O_RDWR模式
    // 注意不能重复打开相同文件,并且需要更新文件打开列表
    if(!is_file(path)) throw FileNotFoundError(path);
    if(path2fd_.count(path)) throw FileNotClosedError(path);
    int fd = open(path.c_str(),O_RDWR);
    //更新文件打开列表操作
    fd2path_[fd] = path;
    path2fd_[path] = fd;
    return fd;
}

close_file(int fd)

根据文件句柄查看文件是否未关闭,关闭后即可清理哈希表中的映射

/**
 * @description:用于关闭指定路径文件 
 * @param {int} fd 打开的文件的文件句柄
 */
void DiskManager::close_file(int fd) {
    // Todo:
    // 调用close()函数
    // 注意不能关闭未打开的文件,并且需要更新文件打开列表
    if(!fd2path_.count(fd)){//该文件未打开
        throw FileNotOpenError(fd);
    }
    close(fd);
    path2fd_.erase(fd2path_[fd]);
    fd2path_.erase(fd);
}

DiskManager::write_page(int fd, page_id_t page_no, const char *offset, int num_bytes)

fseek(FILE *stream, long offset, int whence);

1.offset表示文件指针的偏移量

SEEK_SET:基准位置为文件开头,即offset表示距离文件开头的偏移量。

SEEK_CUR:基准位置为文件当前位置,即offset表示距离文件当前位置的偏移量。

SEEK_END:基准位置为文件末尾,即offset表示距离文件末尾的偏移量。
2.whence表示偏移量的基准位置

当whence为SEEK_SET时,offset表示距离文件开头的偏移量;

当whence为SEEK_CUR时,offset表示距离文件当前位置的偏移量;

当whence为SEEK_END时,offset表示距离文件末尾的偏移量。

void DiskManager::write_page(int fd, page_id_t page_no, const char *offset, int num_bytes) {
    // Todo:
    // 1.lseek()定位到文件头,通过(fd,page_no)可以定位指定页面及其在磁盘文件中的偏移量
    // 2.调用write()函数
    // 注意write返回值与num_bytes不等时 throw InternalError("DiskManager::write_page Error");
    lseek(fd,page_no*PAGE_SIZE,SEEK_SET);
    int write_bytes = write(fd,offset,num_bytes);
    if(write_bytes<0) throw InternalError("DiskManager::write_page Error");
}

DiskManager::read_page(int fd, page_id_t page_no, char *offset, int num_bytes) 

void DiskManager::read_page(int fd, page_id_t page_no, char *offset, int num_bytes) {
    // Todo:
    // 1.lseek()定位到文件头,通过(fd,page_no)可以定位指定页面及其在磁盘文件中的偏移量
    // 2.调用read()函数
    // 注意read返回值与num_bytes不等时,throw InternalError("DiskManager::read_page Error");
    lseek(fd,page_no*PAGE_SIZE,SEEK_SET);
    int read_bytes = read(fd,offset,num_bytes);
    if(read_bytes<0) throw InternalError("DiskManager::read_page Error");
}


http://www.kler.cn/a/137393.html

相关文章:

  • 【考研】数据结构(更新到顺序表)
  • 深度学习之基于yolo的体育运动项目姿态估计识别计数系统
  • 【PTA题目】L1-4 稳赢 分数 15
  • Django学习日志09
  • Rust7.2 More About Cargo and Crates.io
  • vue+element实现多级表头加树结构
  • ubuntu 解决pip/pip3安装库各种报错问题
  • 增速大幅下滑?基础L2博弈成本
  • echarts的使用
  • Go——二、变量和数据类型
  • 爬虫的http和https基础
  • 如何在公网环境下使用笔记本的Potplayer访问本地群晖webdav中的影视资源
  • 蓝桥杯物联网_STM32L071_1_CubMxkeil5基础配置
  • Docker部署FLASK Unicorn并配置Nginx
  • 【Django-02】 Model模型和模型描述对象Meta
  • 类型体系与基本数据类型(题目)
  • WinEdt 11.1编辑器的尝鲜体验
  • vscode c++ 报错identifier “string“ is undefined
  • 海外IP代理科普——API代理是什么?怎么用?
  • 一个快递包裹的跨国之旅