Skip to content

Commit

Permalink
P1:Basic implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
YinshiSanchez committed May 16, 2024
1 parent 95afc60 commit 103cb4e
Show file tree
Hide file tree
Showing 9 changed files with 312 additions and 68 deletions.
148 changes: 141 additions & 7 deletions src/buffer/buffer_pool_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
//===----------------------------------------------------------------------===//

#include "buffer/buffer_pool_manager.h"
#include <mutex>

#include "common/config.h"
#include "common/exception.h"
#include "common/macros.h"
#include "storage/page/page_guard.h"
Expand All @@ -22,9 +24,9 @@ BufferPoolManager::BufferPoolManager(size_t pool_size, DiskManager *disk_manager
LogManager *log_manager)
: pool_size_(pool_size), disk_scheduler_(std::make_unique<DiskScheduler>(disk_manager)), log_manager_(log_manager) {
// TODO(students): remove this line after you have implemented the buffer pool manager
throw NotImplementedException(
"BufferPoolManager is not implemented yet. If you have finished implementing BPM, please remove the throw "
"exception line in `buffer_pool_manager.cpp`.");
// throw NotImplementedException(
// "BufferPoolManager is not implemented yet. If you have finished implementing BPM, please remove the throw "
// "exception line in `buffer_pool_manager.cpp`.");

// we allocate a consecutive memory space for the buffer pool
pages_ = new Page[pool_size_];
Expand All @@ -38,21 +40,137 @@ BufferPoolManager::BufferPoolManager(size_t pool_size, DiskManager *disk_manager

BufferPoolManager::~BufferPoolManager() { delete[] pages_; }

auto BufferPoolManager::NewPage(page_id_t *page_id) -> Page * { return nullptr; }
auto BufferPoolManager::NewPage(page_id_t *page_id) -> Page * {
std::lock_guard lg(latch_);
frame_id_t frame_id(-1);
if (!free_list_.empty()) { // find from free list
frame_id = free_list_.front();
free_list_.pop_front();
} else { // find from replacer
replacer_->Evict(&frame_id);
}

// allocate page
if (frame_id >= 0) {
// remove old page
page_table_.erase(pages_[frame_id].page_id_);

// dirty page, need to write back to disk
if (pages_[frame_id].IsDirty()) {
FlushFrame(frame_id);
}

// insert new frame
replacer_->RecordAccess(frame_id);
replacer_->SetEvictable(frame_id, false);

// allocate new page
*page_id = AllocatePage();
page_table_[*page_id] = frame_id;
pages_[frame_id].page_id_ = *page_id;
pages_[frame_id].pin_count_ = 1;
pages_[frame_id].is_dirty_ = false;

return &pages_[frame_id];
}
return nullptr;
}

auto BufferPoolManager::FetchPage(page_id_t page_id, [[maybe_unused]] AccessType access_type) -> Page * {
std::lock_guard lg(latch_);
auto page_itr = page_table_.find(page_id);
frame_id_t frame_id(-1);

// page exists in buffer pool
if (page_itr != page_table_.end()) {
frame_id = page_itr->second;
replacer_->RecordAccess(frame_id);
replacer_->SetEvictable(frame_id, false);
++pages_[frame_id].pin_count_;
return &pages_[frame_id];
}

if (!free_list_.empty()) { // find from free list
frame_id = free_list_.front();
free_list_.pop_front();
} else { // find from replacer
if (replacer_->Evict(&frame_id) && pages_[frame_id].IsDirty()) {
// dirty page, need to write back to disk
FlushFrame(frame_id);
}
}

if (frame_id >= 0) {
// remove old page
page_table_.erase(pages_[frame_id].page_id_);

// insert new frame
replacer_->RecordAccess(frame_id);
replacer_->SetEvictable(frame_id, false);

// allocate new page
page_table_[page_id] = frame_id;
pages_[frame_id].page_id_ = page_id;
pages_[frame_id].pin_count_ = 1;
pages_[frame_id].is_dirty_ = false;
ReadFrame(frame_id);

return &pages_[frame_id];
}

return nullptr;
}

auto BufferPoolManager::UnpinPage(page_id_t page_id, bool is_dirty, [[maybe_unused]] AccessType access_type) -> bool {
std::lock_guard lg(latch_);
auto page_itr = page_table_.find(page_id);
pages_[page_itr->second].is_dirty_ |= is_dirty;
if (page_itr != page_table_.end() && pages_[page_itr->second].pin_count_ > 0) {
--pages_[page_itr->second].pin_count_;
if (pages_[page_itr->second].pin_count_ == 0) {
replacer_->SetEvictable(page_itr->second, true);
}
return true;
}
return false;
}

auto BufferPoolManager::FlushPage(page_id_t page_id) -> bool { return false; }
auto BufferPoolManager::FlushPage(page_id_t page_id) -> bool {
BUSTUB_ASSERT(page_id != INVALID_PAGE_ID, "invalid page id!");
std::lock_guard lg(latch_);
auto page_itr = page_table_.find(page_id);
if (page_itr != page_table_.end()) {
FlushFrame(page_itr->second);
return true;
}
return false;
}

void BufferPoolManager::FlushAllPages() {}
void BufferPoolManager::FlushAllPages() {
std::lock_guard lg(latch_);
for ([[maybe_unused]] auto [_, frame_id] : page_table_) { // NOTLINT
FlushFrame(frame_id);
}
}

auto BufferPoolManager::DeletePage(page_id_t page_id) -> bool { return false; }
auto BufferPoolManager::DeletePage(page_id_t page_id) -> bool {
std::lock_guard lg(latch_);
auto page_itr = page_table_.find(page_id);
if (page_itr == page_table_.end()) {
return true;
}
if (pages_[page_itr->second].pin_count_ != 0) {
return false;
}
frame_id_t frame_id = page_itr->second;
replacer_->Remove(frame_id);
free_list_.push_back(frame_id);
if (pages_[frame_id].IsDirty()) {
FlushFrame(frame_id);
}
DeallocatePage(page_id);
return true;
}

auto BufferPoolManager::AllocatePage() -> page_id_t { return next_page_id_++; }

Expand All @@ -64,4 +182,20 @@ auto BufferPoolManager::FetchPageWrite(page_id_t page_id) -> WritePageGuard { re

auto BufferPoolManager::NewPageGuarded(page_id_t *page_id) -> BasicPageGuard { return {this, nullptr}; }

void BufferPoolManager::FlushFrame(frame_id_t frame_id) {
auto promise = disk_scheduler_->CreatePromise();
auto future = promise.get_future();
disk_scheduler_->Schedule({true, pages_[frame_id].GetData(), pages_[frame_id].GetPageId(), std::move(promise)});
BUSTUB_ENSURE(future.get(), "write page failed!");
pages_[frame_id].is_dirty_ = false;
}

void BufferPoolManager::ReadFrame(frame_id_t frame_id) {
auto promise = disk_scheduler_->CreatePromise();
auto future = promise.get_future();
disk_scheduler_->Schedule({false, pages_[frame_id].GetData(), pages_[frame_id].GetPageId(), std::move(promise)});
BUSTUB_ENSURE(future.get(), "read page failed!");
pages_[frame_id].is_dirty_ = false;
}

} // namespace bustub
41 changes: 24 additions & 17 deletions src/buffer/lru_k_replacer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,13 @@
//===----------------------------------------------------------------------===//

#include "buffer/lru_k_replacer.h"
#include <sys/types.h>
#include <cstddef>
#include <cstdint>
#include <exception>
#include <iostream>
#include <mutex>
#include <string>
#include <utility>
#include <vector>
#include "common/config.h"
Expand All @@ -29,7 +33,7 @@ constexpr size_t INF = SIZE_MAX >> 1;

// LRUKNode

LRUKNode::LRUKNode(const size_t k) : history_(k + 1), k_(k) { k_distance_ = INF; };
LRUKNode::LRUKNode(const size_t k) : history_(k + 1), k_(k) { k_distance_ = INF; }

auto LRUKNode::operator<(const LRUKNode &rhs) const -> bool { return false; }

Expand All @@ -47,19 +51,20 @@ void LRUKNode::Access(const size_t timestamp) {
}
history_[end_++] = timestamp;
end_ = QUEUE_POS(end_, k_);
if (QUEUE_SIZE(start_, end_, k_) != k_) {
k_distance_ = SIZE_MAX - timestamp;
#ifdef BI_HEAP
#else
if (QUEUE_SIZE(start_, end_, k_) < k_) {
k_distance_ = SIZE_MAX - history_[start_];
} else {
k_distance_ = INF - history_[start_];
}
#endif
}

auto LRUKNode::Valid() const -> bool { return k_ != INF; }

void LRUKNode::SetInvalid() { k_ = INF; }

auto LRUKNode::KDistance() -> size_t { return k_distance_; }

// NodeHeap

NodeHeap::NodeHeap(const size_t node_num, std::vector<LRUKNode> &node_ref)
Expand All @@ -68,6 +73,7 @@ NodeHeap::NodeHeap(const size_t node_num, std::vector<LRUKNode> &node_ref)
}

void NodeHeap::Push(const frame_id_t frame_id) {
BUSTUB_ENSURE(static_cast<size_t>(frame_id) < frame_pos_map_.size(), "overflow frame id!");
if (frame_pos_map_[frame_id] == INF) { // new entry
size_t cur_pos = ++frame_heap_[0];
auto parent_pos = cur_pos >> 1;
Expand Down Expand Up @@ -110,25 +116,22 @@ auto NodeHeap::Pop() -> frame_id_t {
}
} else { // cur_frame is non-evictable
auto next_pos = queue[i] << 1;
if (next_pos <= static_cast<uint64_t>(frame_heap_[0])) { // left child

if (node_ref_[frame_heap_[next_pos]].KDistance() > max_distance) {
temp_queue[temp_size++] = next_pos;
++next_pos;
}
if (next_pos <= static_cast<uint64_t>(frame_heap_[0]) &&
node_ref_[frame_heap_[next_pos]].KDistance() > max_distance) { // left child
temp_queue[temp_size++] = next_pos;
++next_pos;
}
if (next_pos <= static_cast<uint64_t>(frame_heap_[0]) &&
node_ref_[frame_heap_[next_pos]].KDistance() > max_distance) { // left child
temp_queue[temp_size++] = next_pos;
}
++next_pos;
if (next_pos <= static_cast<uint64_t>(frame_heap_[0]) &&
node_ref_[frame_heap_[next_pos]].KDistance() > max_distance) { // right child
temp_queue[temp_size++] = next_pos;
}
}
}
queue_size = temp_size;
queue = std::move(temp_queue);
}

if (max_frame > 0) {
if (max_frame >= 0) {
// swap min frame and evictable max frame
auto min_frame = frame_heap_[frame_heap_[0]];
frame_heap_[frame_pos_map_[max_frame]] = min_frame;
Expand All @@ -151,10 +154,13 @@ void NodeHeap::Remove(const frame_id_t frame_id) {

// move the lastest frame to cur pos
auto cur_frame = frame_heap_[frame_heap_[0]];
frame_heap_[pos] = cur_frame;
frame_pos_map_[cur_frame] = pos;
--frame_heap_[0];

// correct heap tree;
Amend(pos);
frame_pos_map_[frame_id] = INF;
}

void NodeHeap::Amend(size_t pos) {
Expand Down Expand Up @@ -225,6 +231,7 @@ void LRUKReplacer::SetEvictable(const frame_id_t frame_id, bool set_evictable) {

void LRUKReplacer::Remove(const frame_id_t frame_id) {
BUSTUB_ASSERT(static_cast<size_t>(frame_id) < replacer_size_, "invalid frame id!");
std::lock_guard lg(latch_);
BUSTUB_ASSERT(node_store_[frame_id].Evictable(), "try to evict a non-evictable frame");
if (node_store_[frame_id].Valid()) {
node_store_[frame_id].SetInvalid();
Expand Down
5 changes: 5 additions & 0 deletions src/include/buffer/buffer_pool_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -208,5 +208,10 @@ class BufferPoolManager {
}

// TODO(student): You may add additional private members and helper functions

// shoud get latch_ before excute this function
void FlushFrame(frame_id_t frame_id);

void ReadFrame(frame_id_t frame_id);
};
} // namespace bustub
14 changes: 12 additions & 2 deletions src/include/buffer/lru_k_replacer.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//

#pragma once
#define BI_HEAP

#include <cstddef>
#include <limits>
Expand Down Expand Up @@ -74,19 +75,28 @@ class LRUKNode {

void SetInvalid();

auto KDistance() -> size_t;
auto KDistance() const -> size_t { return k_distance_; }

void Access(size_t timestamp);

#ifdef BI_HEAP
auto K() const -> size_t { return k_; }

auto Distance() const -> size_t { return distance_; }
#endif

private:
/** History of last seen K timestamps of this page. Least recent timestamp stored in front. */
// Remove maybe_unused if you start using them. Feel free to change the member variables as you want.

std::vector<size_t> history_;
size_t start_{0};
size_t end_{0};
size_t k_;
size_t k_distance_;
#ifdef BI_HEAP
size_t k_;
size_t distance_;
#endif
bool is_evictable_{false};
};

Expand Down
Loading

0 comments on commit 103cb4e

Please sign in to comment.