CMU 15-445 Project #1 - Buffer Pool(Task #3 - Buffer Pool Manager Instance)

Task #3 - Buffer Pool Manager Instance

  • 一、题目链接
  • 二、准备工作
  • 三、部分实现

在这里插入图片描述

一、题目链接


二、准备工作

见 CMU 15-445 Project #0 - C++ Primer 中的准备工作。


三、部分实现

首先要区分缓冲池中 PageFrame ,这个其实和操作系统分页管理中页面页框的关系是类似的。页框是内存中一个个实际的空间,但它只是空间,没有内容。而页面则是被放置在页框中的实际内容,同时每一个内存中的页面都有它的外存映像,他们共用同一个 page_id,并通过脏位标识数据回写。

此外,还有几个问题在实现时要注意:

  1. FetchPgImp 中不管页面是已经存在与缓冲池,还是通过LRU-K置换得到,都需要
  2. UnpinPgImp 中的脏位修改仅限于 false -> true 的单向修改,因为一个页面脏位 true -> false 的修改必须与外存回写 WritePage 配合。
  3. DeletePgImp 中在进行删除前也要通过脏位判断是否需要回写。

NewPgImp

auto NewPgImp(page_id_t *page_id) -> Page * override {
    std::scoped_lock<std::mutex> locker(latch_);

    frame_id_t frame_id = 0;  // 用于记录分配给新页面的页框号

    /* 如果空闲链表不为空,直接从空闲链表中获取一个空的页框来初始化页面;
     * 否则需要通过LRU-K淘汰现有page,然后在对应frame中新建page。 */
    if (!free_list_.empty()) {
        /* 从空闲链表中获取frame_id */
        frame_id = free_list_.front();
        free_list_.pop_front();
    } else {
        /* 通过LRU-K获取应该被淘汰的页框 */
        if (!replacer_->Evict(&frame_id)) {
            *page_id = INVALID_PAGE_ID;
            return nullptr;
        }

        /* 如果脏位为true需要进行回写 */
        if (pages_[frame_id].IsDirty()) {
            disk_manager_->WritePage(pages_[frame_id].GetPageId(), pages_[frame_id].GetData());
        }

        /* 从page_table_删除页面和页框之间的映射 */
        page_table_->Remove(pages_[frame_id].GetPageId());
    }

    /* 获取页面编号 */
    *page_id = AllocatePage();

    /* 初始化页面元数据 */
    pages_[frame_id].page_id_ = *page_id;
    pages_[frame_id].pin_count_++;
    pages_[frame_id].is_dirty_ = false;

    /* 在可扩展哈希表中建立page_id与frame_id的编号 */
    page_table_->DoInsert(*page_id, frame_id);

    /* 记录指定页框的访问并将该页框设置为不可驱逐 */
    replacer_->RecordAccess(frame_id);
    replacer_->SetEvictable(frame_id, false);

    return pages_ + frame_id;
}

FetchPgImp

auto FetchPgImp(page_id_t page_id) -> Page * override {
    std::scoped_lock<std::mutex> locker(latch_);

    int frame_id;  // 待操作的页框号

    /* 如果待查找页面位于缓冲池,直接返回即可 */
    if (page_table_->Find(page_id, frame_id)) {
        /* 增加页面访问次数 */
        pages_[frame_id].pin_count_++;

        /* 记录指定页框的访问并将该页框设置为不可驱逐 */
        replacer_->RecordAccess(frame_id);
        replacer_->SetEvictable(frame_id, false);

        return pages_ + frame_id;
    }

    /* 如果空闲链表不为空,直接从空闲链表中获取一个空的页框来初始化页面;
     * 否则需要通过LRU-K淘汰现有page,然后在对应frame中新建page。 */
    if (!free_list_.empty()) {
        /* 从空闲链表中获取frame_id */
        frame_id = free_list_.front();
        free_list_.pop_front();
    } else {
        /* 通过LRU-K获取应该被淘汰的页框 */
        if (!replacer_->Evict(&frame_id)) {
            return nullptr;
        }

        /* 如果脏位为true需要进行回写 */
        if (pages_[frame_id].IsDirty()) {
            disk_manager_->WritePage(pages_[frame_id].GetPageId(), pages_[frame_id].GetData());
        }

        /* 从page_table_删除页面和页框之间的映射 */
        page_table_->Remove(pages_[frame_id].GetPageId());
    }

    /* 初始化页面元数据 */
    pages_[frame_id].page_id_ = page_id;
    pages_[frame_id].is_dirty_ = false;
    pages_[frame_id].pin_count_++;

    /* 写入页面的数据 */
    disk_manager_->ReadPage(page_id, pages_[frame_id].GetData());

    /* 在可扩展哈希表中建立page_id与frame_id的编号 */
    page_table_->DoInsert(page_id, frame_id);

    /* 记录指定页框的访问并将该页框设置为不可驱逐 */
    replacer_->RecordAccess(frame_id);
    replacer_->SetEvictable(frame_id, false);

    return pages_ + frame_id;
}

UnpinPgImp

auto UnpinPgImp(page_id_t page_id, bool is_dirty) -> bool override {
    std::scoped_lock<std::mutex> locker(latch_);

    int frame_id;  // 待操作的页框号

    /* 查询并修改缓冲池中指定页面的信息 */
    if (page_table_->Find(page_id, frame_id)) {
        /* 如果当前页面pin_count_已经为0直接返回false */
        if (pages_[frame_id].GetPinCount() == 0) {
            return false;
        }

        /* 这里的脏位变换只支持从false到true,从true到false需要与回写配合 */
        if (!pages_[frame_id].IsDirty() && is_dirty) {
            pages_[frame_id].is_dirty_ = true;
        }

        /* 如果当前操作使得pin_count_值为0,需要将对应页面设置为可驱逐。 */
        if (--pages_[frame_id].pin_count_ == 0) {
            replacer_->SetEvictable(frame_id, true);
        }

        return true;
    }

    return false;
}

FlushPgImp

auto FlushPgImp(page_id_t page_id) -> bool override {
    std::scoped_lock<std::mutex> locker(latch_);

    int frame_id;  // 待操作的页框号

    /* 如果指定页面存在且脏位为true需要进行回写 */
    if (page_table_->Find(page_id, frame_id)) {
        if (pages_[frame_id].IsDirty()) {
            disk_manager_->WritePage(pages_[frame_id].GetPageId(), pages_[frame_id].GetData());
            pages_[frame_id].is_dirty_ = false;
        }

        return true;
    }

    return false;
}

FlushAllPgsImp

void FlushAllPgsImp() override {
    std::scoped_lock<std::mutex> locker(latch_);

    /* 依次回写所有的脏页 */
    for (int frame_id = 0; frame_id < static_cast<int>(pool_size_); frame_id++) {
        if (pages_[frame_id].GetPageId() != INVALID_PAGE_ID && pages_[frame_id].IsDirty()) {
            disk_manager_->WritePage(pages_[frame_id].GetPageId(), pages_[frame_id].GetData());
            pages_[frame_id].is_dirty_ = false;
        }
    }
}

DeletePgImp

auto DeletePgImp(page_id_t page_id) -> bool override {
    std::scoped_lock<std::mutex> locker(latch_);

    int frame_id;  // 待操作的页框号

    if (page_table_->Find(page_id, frame_id)) {
        /* 无法删除被固定的页面 */
        if (pages_[frame_id].GetPinCount() > 0) {
            return false;
        }

        /* 如果脏位为true需要进行回写 */
        if (pages_[frame_id].IsDirty()) {
            disk_manager_->WritePage(pages_[frame_id].GetPageId(), pages_[frame_id].GetData());
        }

        /* 从page_table_和replacer_中删除页面的相关信息 */
        page_table_->Remove(page_id);
        replacer_->Remove(frame_id);

        /* 重置页面的在内存中的缓存和元数据 */
        pages_[frame_id].ResetMemory();
        pages_[frame_id].page_id_ = INVALID_PAGE_ID;
        pages_[frame_id].is_dirty_ = false;
        pages_[frame_id].pin_count_ = 0;

        /* 将页框归还给空闲链表 */
        free_list_.emplace_back(frame_id);

        /* 重置页面在外存中的数据 */
        DeallocatePage(page_id);

        return true;
    }

    return true;
}

提交后的结果如下,所有测试用例全部通过,由于没有对并发性能进行优化,所以执行效率一般。

CMU 15-445 Project #1 - Buffer Pool(Task #3 - Buffer Pool Manager Instance)_第1张图片

CMU 15-445 Project #1 - Buffer Pool(Task #3 - Buffer Pool Manager Instance)_第2张图片

在这里插入图片描述

你可能感兴趣的:(CMU,15-445(FALL,2022),数据结构,数据库内核)