Rucbase缓冲池管理器——LRU替换策略

1.需求

本题需要实现缓冲池管理器BufferPoolManager和缓冲池替换策略Replacer相关的接口,缓冲池管理器负责管理缓冲池中的页面在内外存的交换,缓冲池替换策略主要负责缓冲区页面的淘汰和查找。学生可以阅读项目结构文档中缓冲池管理器的相关说明,以及代码框架中src/storage和src/replacer文件夹下的代码文件。

对于缓冲池替换策略Replacer,学生需要实现一个Replacer的子类LRUReplacer,LRUReplacer实现了缓冲池页面替换的LRU策略,需要实现的接口如下:

(1) bool LRUReplacer::victim(frame_id_t* frame_id);

该接口的功能是选择并淘汰缓冲池中一个页面。如果成功找到要淘汰的页面,则函数返回值为true;否则,返回值为false。被淘汰的页面所在的帧由参数frame_id返回。

(2) void LRUReplacer::pin(frame_id_t frame_id);

该接口的功能是固定住一个帧中的页面,代表该页面正在使用,不可被换出,参数frame_id指定了帧的编号。

(3) void LRUReplacer::unpin(frame_id_t frame_id);

该接口的功能是取消固定一个帧中的页面,当该页面使用完毕时调用unpin函数取消对该页面的固定,参数frame_id指定了帧的编号。

2.功能实现

rucbase-lab/src/replacer/lru_replacer.cpp


/**
 * @description: 使用LRU策略删除一个victim frame,并返回该frame的id
 * @param {frame_id_t*} frame_id 被移除的frame的id,如果没有frame被移除返回nullptr
 * @return {bool} 如果成功淘汰了一个页面则返回true,否则返回false
 */
bool LRUReplacer::victim(frame_id_t* frame_id) {
    // C++17 std::scoped_lock
    // 它能够避免死锁发生,其构造函数能够自动进行上锁操作,析构函数会对互斥量进行解锁操作,保证线程安全。
    std::scoped_lock lock{latch_};  //  如果编译报错可以替换成其他lock

    // Todo:
    //  利用lru_replacer中的LRUlist_,LRUHash_实现LRU策略
    //  选择合适的frame指定为淘汰页面,赋值给*frame_id

    if(LRUhash_.empty()) return false;//没有frame_id可删

    frame_id_t to_delete = LRUlist_.back();//尾部为最久未使用
    *frame_id = to_delete;
    LRUlist_.pop_back();//删除最久没用、unpinned pages的frame id
    LRUhash_.erase(to_delete);//同时删除哈希映射

    return true;
}
/**
 * @description: 固定指定的frame,即该页面无法被淘汰
 * @param {frame_id_t} 需要固定的frame的id
 */
void LRUReplacer::pin(frame_id_t frame_id) {
    std::scoped_lock lock{latch_};
    // Todo:
    // 固定指定id的frame
    // 在数据结构中移除该frame
    auto it = LRUhash_.find(frame_id);
    if(it!= LRUhash_.end()){//在表中说明unpin 可能被淘汰
        LRUlist_.erase(LRUhash_[frame_id]);
        LRUhash_.erase(frame_id);
    }
    return ;
}

/**
 * @description: 取消固定一个frame,代表该页面可以被淘汰
 * @param {frame_id_t} frame_id 取消固定的frame的id
 */
void LRUReplacer::unpin(frame_id_t frame_id) {
    // Todo:
    //  支持并发锁
    //  选择一个frame取消固定
    std::scoped_lock lock{latch_};
    auto it = LRUhash_.find(frame_id);
    if(it == LRUhash_.end()){//不在表中,说明Pin
        while(LRUhash_.size() >= max_size_){//超过最大缓存
            frame_id_t to_delete = LRUlist_.front();
            LRUlist_.pop_front();
            LRUhash_.erase(to_delete);
        }
        LRUlist_.push_front(frame_id);//最近使用放队首
        LRUhash_[frame_id] = LRUlist_.begin();//unpin
    }
}

你可能感兴趣的:(数据库,数据库)