0 实验结果
1 任务总结
本章按照任务书,需要完成
- LRU-K替换策略
- 磁盘调度器——后台线程接收请求,处理数据的读/写。
- 缓冲池管理——使用上面完成的功能,来对抽象的页操作。
1.1 LRU-K替换策略
每个函数的说明都很清楚,按照指示来写即可。
主要说明一些坑点
1.1.1 变量及其作用
时间戳这里要提一下,因为RecordAccess
的访问很频繁,时间很短,获取真实的时间戳作用不大。
所以可以每RecordAccess
一次,就递增当前的时间戳,计算 K距离时,通过当前时间戳和从当前开始向前数第K次的作差。
// 可以被淘汰置换出的帧数量
size_t curr_size_{0};
// 当前的时间戳
size_t current_timestamp_{0};
1.1.2 坑点
需要明确LRU-K算法,这里算法有点特殊
1.1.2.1 当一个帧访问次数不到K次时,K-距离都是INF,此时比较的是帧最早访问(即第一次)的时间,时间越早,越先被淘汰。
举个例子:当K=3时,此时因为帧1和帧2都没有访问到3次,而帧1最早访问,所以淘汰帧1。
frame_id | time_stamp |
---|---|
1 | 0 |
2 | 1 |
1 | 2 |
1.2 磁盘调度器
实现简单,没有坑点,过~
1.3 缓冲池管理
一开始对list,map,page分别上锁,测试无法通过,后改为使用大颗粒锁(即函数从头到尾锁定)。
1.3.1 NewPage
创建新的页面之后,先使用RecordAccess
创建节点,再SetEvictable
将其设置为Pin。
修改page的元数据,包括:
page_id_,pin_count_,is_dirty_ 等元数据
1.3.2 FetchPage
获取页面的时候,如果缓冲池中本来就存在,则pin_count_ 需要+1,如果是通过淘汰其他页面得到的,pin_count_ 需要重置为1。
1.3.3 UnpinPage
传入此函数的is_dirty使用注意:
只有当页面不脏时,需要设置此位为传入的参数。
并且多线程环境下 一定要 每次都执行判断is_dirty并赋值操作。
我在这里遇到的问题,就是它导致的。
[ 2.75] get 2: total_cnt=648 throughput=251.583 avg_throughput=235.808
page seed not consistent: seed_=0 seed=1
2 知识总结
2.1 std::list
一个双向链表容器
尾插入:push_back
头插入: push_front
删除元素:
pop_back
pop_front
erase
获取元素:
front()
back()
2.2 std::optional
表示一个可能存在也可能不存在的值,作用是:使用std::nullopt
,避免使用 nullptr
或特殊值(如 -1
或 0
)来表示“无值”的情况。
方法:
emplace
2.3 std::promise
并发编程中传递值或异常.
可以与 std::future
一起使用,以实现异步操作.
std::promise
可以存储任何类型的值.
std::future::get()
是一个阻塞调用,它会一直等待,直到 std::promise
设置了值或异常.
2.4 std::unordered_map
std::map
是一个有序的关联容器,基于红黑树(一种自平衡二叉搜索树)实现,
平均时间复杂度为 O(log n)。
由于红黑树的结构,内存占用相对较高。
std::unordered_map
是一个无序的关联容器,基于哈希表实现。
平均时间复杂度为 O(1),最坏情况下为 O(n),内存占用相对较低。
std::unordered_map的赋值
std::unordered_map<int,complex_type>data_src;1. 赋值运算符拷贝
std::unordered_map<int,complex_type>data_src_copy = data_src;
2. 拷贝构造函数
std::unordered_map<int,complex_type>data_src_copy(data_src);
键和值 都会被拷贝到新的 std::unordered_map
容器中,如果是指针类型,仅复制指针地址。
complex_type& operator=(const complex_type& that){std::cout << "赋值重载" << std::endl;this->age = that.age;this->name = that.name;return *this;}// 结果============有参构造函数拷贝构造函数============有参构造函数默认构造函数赋值重载============拷贝构造函数拷贝构造函数============赋值重载赋值重载============有参构造函数赋值重载============syh dd// 代码std::unordered_map<int,complex_type>data_src;std::cout << "============" << std::endl;data_src.emplace(1,complex_type(10, "syh"));std::cout << "============" << std::endl;data_src[2] = complex_type(20,"mike");std::cout << "============" << std::endl;std::unordered_map<int,complex_type>data_src_copy(data_src);// 因为有两个值,所以发生了两次拷贝std::cout << "============" << std::endl;data_src_copy = data_src;std::cout << "============" << std::endl;data_src_copy[1] = complex_type(57,"dd");std::cout << "============" << std::endl;std::cout << data_src[1].name<<" " << data_src_copy[1].name << std::endl;