Commit 439de35b authored by z2z63's avatar z2z63
Browse files

fix(BufferPoolManager): complete concurrency control, rewrite `flush_all_pages`

Showing with 37 additions and 29 deletions
+37 -29
......@@ -16,15 +16,15 @@ See the Mulan PSL v2 for more details. */
* @return {bool} true: 可替换帧查找成功 , false: 可替换帧查找失败
* @param {frame_id_t*} frame_id 帧页id指针,返回成功找到的可替换帧id
*/
bool BufferPoolManager::find_victim_page(frame_id_t* frame_id) {
bool BufferPoolManager::find_victim_page(frame_id_t *frame_id) {
// Todo:
// 1 使用BufferPoolManager::free_list_判断缓冲池是否已满需要淘汰页面
// 1.1 未满获得frame
// 1.2 已满使用lru_replacer中的方法选择淘汰页面
if(free_list_.empty()){
if (free_list_.empty()) {
return replacer_->victim(frame_id);
}else{
} else {
*frame_id = free_list_.front();
free_list_.pop_front();
return true;
......@@ -43,7 +43,7 @@ void BufferPoolManager::update_page(Page *page, PageId new_page_id, frame_id_t n
// 2 更新page table
// 3 重置page的data,更新page id
auto page_id = page->get_page_id();
if(page->is_dirty()){
if (page->is_dirty()) {
disk_manager_->write_page(page_id.fd, page_id.page_no, page->get_data(), PAGE_SIZE);
page->is_dirty_ = false;
}
......@@ -51,7 +51,7 @@ void BufferPoolManager::update_page(Page *page, PageId new_page_id, frame_id_t n
page_table_[new_page_id] = new_frame_id;
Page* ptr = &pages_[new_frame_id];
Page *ptr = &pages_[new_frame_id];
ptr->is_dirty_ = false;
// disk_manager_->read_page(new_page_id.fd, new_page_id.page_no, ptr->data_, PAGE_SIZE);
ptr->id_ = new_page_id;
......@@ -64,7 +64,7 @@ void BufferPoolManager::update_page(Page *page, PageId new_page_id, frame_id_t n
* @return {Page*} 若获得了需要的页则将其返回,否则返回nullptr
* @param {PageId} page_id 需要获取的页的PageId
*/
Page* BufferPoolManager::fetch_page(PageId page_id) {
Page *BufferPoolManager::fetch_page(PageId page_id) {
//Todo:
// 1. 从page_table_中搜寻目标页
// 1.1 若目标页有被page_table_记录,则将其所在frame固定(pin),并返回目标页。
......@@ -73,16 +73,16 @@ Page* BufferPoolManager::fetch_page(PageId page_id) {
// 3. 调用disk_manager_的read_page读取目标页到frame
// 4. 固定目标页,更新pin_count_
// 5. 返回目标页
if(page_table_.find(page_id) != page_table_.end()){ // 在buffer pool中
Page* p = &pages_[page_table_[page_id]];
std::scoped_lock lock{latch_};
if (page_table_.find(page_id) != page_table_.end()) { // 在buffer pool中
Page *p = &pages_[page_table_[page_id]];
// pin_cout_ == 0时此页还能留在buffer_pool中,可能已经unpinned,确保已经pin
replacer_->pin(page_table_[page_id]);
p->pin_count_++;
return p;
}
frame_id_t victim;
if(!find_victim_page(&victim)){
if (!find_victim_page(&victim)) {
return nullptr; // 没有可淘汰页或空闲页,无法加载到buffer pool中
}
update_page(&pages_[victim], page_id, victim);
......@@ -109,20 +109,20 @@ bool BufferPoolManager::unpin_page(PageId page_id, bool is_dirty) {
// 2.2.1 若自减后等于0,则调用replacer_的Unpin
// 3 根据参数is_dirty,更改P的is_dirty_
std::scoped_lock lock{latch_};
if(page_table_.find(page_id) == page_table_.end()){
if (page_table_.find(page_id) == page_table_.end()) {
return false;
}
Page* p = &pages_[page_table_[page_id]];
Page *p = &pages_[page_table_[page_id]];
bool retval = p->pin_count_ > 0;
if(p->pin_count_ == 0){
if (p->pin_count_ == 0) {
return false;
}else if(p->pin_count_ > 0){
p->pin_count_ --;
} else if (p->pin_count_ > 0) {
p->pin_count_--;
}
if(p->pin_count_ == 0){
if (p->pin_count_ == 0) {
replacer_->unpin(page_table_[page_id]);
}
if(is_dirty){
if (is_dirty) {
p->is_dirty_ = true; // 避免`p->is_dirty_`被`false`覆盖
}
return retval;
......@@ -142,10 +142,10 @@ bool BufferPoolManager::flush_page(PageId page_id) {
// 3. 更新P的is_dirty_
std::scoped_lock lock{latch_};
auto it = page_table_.find(page_id);
if(it == page_table_.end()){
if (it == page_table_.end()) {
return false;
}
Page* p = &pages_[it->second];
Page *p = &pages_[it->second];
disk_manager_->write_page(page_id.fd, page_id.page_no, p->data_, PAGE_SIZE);
p->is_dirty_ = false;
return true;
......@@ -156,15 +156,15 @@ bool BufferPoolManager::flush_page(PageId page_id) {
* @return {Page*} 返回新创建的page,若创建失败则返回nullptr
* @param {PageId*} page_id 当成功创建一个新的page时存储其page_id
*/
Page* BufferPoolManager::new_page(PageId* page_id) {
Page *BufferPoolManager::new_page(PageId *page_id) {
// 1. 获得一个可用的frame,若无法获得则返回nullptr
// 2. 在fd对应的文件分配一个新的page_id
// 3. 将frame的数据写回磁盘
// 4. 固定frame,更新pin_count_
// 5. 返回获得的page
std::scoped_lock lock{latch_};
frame_id_t victim;
if(!find_victim_page(&victim)){
if (!find_victim_page(&victim)) {
return nullptr;
}
page_id->page_no = disk_manager_->allocate_page(page_id->fd);
......@@ -184,15 +184,20 @@ bool BufferPoolManager::delete_page(PageId page_id) {
// 2. 若目标页的pin_count不为0,则返回false
// 3. 将目标页数据写回磁盘,从页表中删除目标页,重置其元数据,将其加入free_list_,返回true
std::scoped_lock lock{latch_};
auto it = page_table_.find(page_id);
if(it == page_table_.end()){
if (it == page_table_.end()) {
return true;
}
if(pages_[it->second].pin_count_ != 0){
if (pages_[it->second].pin_count_ != 0) {
return false;
}
flush_page(page_id);
memset(&pages_[it->second], 0, sizeof(Page)); // 填充零
Page *page = &pages_[it->second];
if (page->is_dirty_) {
disk_manager_->write_page(page_id.fd, page_id.page_no, page->data_, PAGE_SIZE);
// page->is_dirty_ = false; // no need
}
memset(page, 0, sizeof(Page)); // 填充零
free_list_.push_back(it->second);
page_table_.erase(it);
return true;
......@@ -203,9 +208,12 @@ bool BufferPoolManager::delete_page(PageId page_id) {
* @param {int} fd 文件句柄
*/
void BufferPoolManager::flush_all_pages(int fd) {
for (auto pair: page_table_) {
if(pair.first.fd == fd){
flush_page(pair.first);
std::scoped_lock lock{latch_};
for (frame_id_t i = 0; i < pool_size_; i++) {
auto page_id = pages_[i].get_page_id();
if (page_id.fd == fd) {
disk_manager_->write_page(fd, page_id.page_no, pages_[i].data_, PAGE_SIZE);
}
}
}
\ No newline at end of file
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment