refactored
This commit is contained in:
4
storage/src/bpt.cpp
Normal file
4
storage/src/bpt.cpp
Normal file
@ -0,0 +1,4 @@
|
||||
#include "storage/bpt.hpp"
|
||||
#include "storage/config.h"
|
||||
const b_plus_tree_value_index_t kInvalidValueIndex = -1;
|
||||
const default_numeric_index_t kInvalidNumericIndex = -1;
|
302
storage/src/buffer_pool_manager.cpp
Normal file
302
storage/src/buffer_pool_manager.cpp
Normal file
@ -0,0 +1,302 @@
|
||||
#include "storage/buffer_pool_manager.h"
|
||||
#include <cstring>
|
||||
#include <mutex>
|
||||
#include "storage/config.h"
|
||||
Page::Page() : mem(new char[kPageSize]) {}
|
||||
Page::~Page() { delete[] mem; }
|
||||
void Page::ResetMemory() { memset(mem, 0, kPageSize); }
|
||||
char *Page::GetData() { return mem; }
|
||||
page_id_t Page::GetPageId() { return page_id_; }
|
||||
BasicPageGuard::BasicPageGuard(BasicPageGuard &&that) noexcept {
|
||||
bpm_ = that.bpm_;
|
||||
page_ = that.page_;
|
||||
is_dirty_ = that.is_dirty_;
|
||||
that.bpm_ = nullptr;
|
||||
that.page_ = nullptr;
|
||||
that.is_dirty_ = false;
|
||||
}
|
||||
|
||||
void BasicPageGuard::Drop() {
|
||||
if (bpm_ == nullptr || page_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
bpm_->UnpinPage(page_->GetPageId(), is_dirty_);
|
||||
bpm_ = nullptr;
|
||||
page_ = nullptr;
|
||||
is_dirty_ = false;
|
||||
}
|
||||
|
||||
auto BasicPageGuard::operator=(BasicPageGuard &&that) noexcept -> BasicPageGuard & {
|
||||
if (this == &that) {
|
||||
return *this;
|
||||
}
|
||||
Drop();
|
||||
bpm_ = that.bpm_;
|
||||
page_ = that.page_;
|
||||
is_dirty_ = that.is_dirty_;
|
||||
that.bpm_ = nullptr;
|
||||
that.page_ = nullptr;
|
||||
that.is_dirty_ = false;
|
||||
return *this;
|
||||
}
|
||||
|
||||
BasicPageGuard::~BasicPageGuard() { Drop(); }; // NOLINT
|
||||
|
||||
ReadPageGuard::ReadPageGuard(ReadPageGuard &&that) noexcept : guard_(std::move(that.guard_)) {}
|
||||
|
||||
auto ReadPageGuard::operator=(ReadPageGuard &&that) noexcept -> ReadPageGuard & {
|
||||
if (this == &that) {
|
||||
return *this;
|
||||
}
|
||||
#ifdef ENABLE_ADVANCED_FEATURE
|
||||
if (guard_.page_ != nullptr) {
|
||||
guard_.page_->RUnlatch();
|
||||
}
|
||||
#endif
|
||||
guard_ = std::move(that.guard_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void ReadPageGuard::Drop() {
|
||||
#ifdef ENABLE_ADVANCED_FEATURE
|
||||
if (guard_.page_ != nullptr) {
|
||||
guard_.page_->RUnlatch();
|
||||
}
|
||||
#endif
|
||||
guard_.Drop();
|
||||
}
|
||||
|
||||
ReadPageGuard::~ReadPageGuard() { Drop(); } // NOLINT
|
||||
|
||||
WritePageGuard::WritePageGuard(WritePageGuard &&that) noexcept : guard_(std::move(that.guard_)) {}
|
||||
|
||||
auto WritePageGuard::operator=(WritePageGuard &&that) noexcept -> WritePageGuard & {
|
||||
if (this == &that) {
|
||||
return *this;
|
||||
}
|
||||
#ifdef ENABLE_ADVANCED_FEATURE
|
||||
if (guard_.page_ != nullptr) {
|
||||
guard_.page_->WUnlatch();
|
||||
}
|
||||
#endif
|
||||
guard_ = std::move(that.guard_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void WritePageGuard::Drop() {
|
||||
#ifdef ENABLE_ADVANCED_FEATURE
|
||||
if (guard_.page_ != nullptr) {
|
||||
guard_.page_->WUnlatch();
|
||||
}
|
||||
#endif
|
||||
guard_.Drop();
|
||||
}
|
||||
|
||||
WritePageGuard::~WritePageGuard() { Drop(); } // NOLINT
|
||||
BufferPoolManager::BufferPoolManager(size_t pool_size, size_t replacer_k, DiskManager *disk_manager)
|
||||
: pool_size(pool_size),
|
||||
replacer_k(replacer_k),
|
||||
replacer(pool_size, replacer_k),
|
||||
disk_manager(disk_manager) { // we allocate a consecutive memory space for the buffer pool
|
||||
pages_ = new Page[pool_size];
|
||||
|
||||
// Initially, every page is in the free list.
|
||||
for (size_t i = 0; i < pool_size; ++i) {
|
||||
free_list_.push_back(static_cast<frame_id_t>(i));
|
||||
}
|
||||
}
|
||||
BufferPoolManager::~BufferPoolManager() {
|
||||
FlushAllPages();
|
||||
delete[] pages_;
|
||||
}
|
||||
|
||||
page_id_t BufferPoolManager::AllocatePage() {
|
||||
page_id_t page_id = disk_manager->AllocNewEmptyPageId();
|
||||
return page_id;
|
||||
}
|
||||
|
||||
void BufferPoolManager::DeallocatePage(page_id_t page_id) { disk_manager->DeallocatePage(page_id); }
|
||||
|
||||
size_t BufferPoolManager::GetPoolSize() { return pool_size; }
|
||||
Page *BufferPoolManager::GetPages() { return pages_; }
|
||||
auto BufferPoolManager::NewPage(page_id_t *page_id) -> Page * {
|
||||
#ifdef ENABLE_ADVANCED_FEATURE
|
||||
std::lock_guard<std::mutex> guard(latch);
|
||||
#endif
|
||||
if (!free_list_.empty()) {
|
||||
int internal_page_object_offset = free_list_.front();
|
||||
free_list_.pop_front();
|
||||
Page *page = &pages_[internal_page_object_offset];
|
||||
*page_id = AllocatePage();
|
||||
page_table_.insert({*page_id, internal_page_object_offset});
|
||||
page->is_dirty_ = false;
|
||||
page->page_id_ = *page_id;
|
||||
page->pin_count_ = 1;
|
||||
// page->ResetMemory();
|
||||
replacer.RecordAccess(internal_page_object_offset);
|
||||
replacer.SetEvictable(internal_page_object_offset, false);
|
||||
return page;
|
||||
}
|
||||
frame_id_t victim_frame_id;
|
||||
if (!replacer.TryEvictLeastImportant(victim_frame_id)) {
|
||||
return nullptr;
|
||||
}
|
||||
Page *victim_page_ptr = &pages_[victim_frame_id];
|
||||
if (victim_page_ptr->is_dirty_) {
|
||||
disk_manager->WritePage(victim_page_ptr->page_id_, victim_page_ptr->GetData());
|
||||
}
|
||||
*page_id = AllocatePage();
|
||||
page_table_.erase(victim_page_ptr->page_id_);
|
||||
page_table_.insert({*page_id, victim_frame_id});
|
||||
victim_page_ptr->is_dirty_ = false;
|
||||
victim_page_ptr->pin_count_ = 1;
|
||||
victim_page_ptr->page_id_ = *page_id;
|
||||
victim_page_ptr->ResetMemory();
|
||||
replacer.RecordAccess(victim_frame_id);
|
||||
replacer.SetEvictable(victim_frame_id, false);
|
||||
return victim_page_ptr;
|
||||
}
|
||||
|
||||
auto BufferPoolManager::FetchPage(page_id_t page_id) -> Page * {
|
||||
#ifdef ENABLE_ADVANCED_FEATURE
|
||||
std::lock_guard<std::mutex> guard(latch);
|
||||
#endif
|
||||
if (page_table_.find(page_id) != page_table_.end()) {
|
||||
frame_id_t frame_id = page_table_[page_id];
|
||||
Page *page = &pages_[frame_id];
|
||||
page->pin_count_++;
|
||||
replacer.RecordAccess(frame_id);
|
||||
replacer.SetEvictable(frame_id, false);
|
||||
return page;
|
||||
}
|
||||
if (!free_list_.empty()) {
|
||||
int internal_page_object_offset = free_list_.front();
|
||||
free_list_.pop_front();
|
||||
Page *page = &pages_[internal_page_object_offset];
|
||||
page_table_.insert({page_id, internal_page_object_offset});
|
||||
page->is_dirty_ = false;
|
||||
page->page_id_ = page_id;
|
||||
page->pin_count_ = 1;
|
||||
replacer.RecordAccess(internal_page_object_offset);
|
||||
replacer.SetEvictable(internal_page_object_offset, false);
|
||||
disk_manager->ReadPage(page_id, page->GetData());
|
||||
return page;
|
||||
}
|
||||
frame_id_t victim_frame_id;
|
||||
if (!replacer.TryEvictLeastImportant(victim_frame_id)) {
|
||||
return nullptr;
|
||||
}
|
||||
Page *victim_page_ptr = &pages_[victim_frame_id];
|
||||
if (victim_page_ptr->is_dirty_) {
|
||||
disk_manager->WritePage(victim_page_ptr->page_id_, victim_page_ptr->GetData());
|
||||
}
|
||||
page_table_.erase(victim_page_ptr->page_id_);
|
||||
page_table_.insert({page_id, victim_frame_id});
|
||||
victim_page_ptr->is_dirty_ = false;
|
||||
victim_page_ptr->pin_count_ = 1;
|
||||
victim_page_ptr->page_id_ = page_id;
|
||||
replacer.RecordAccess(victim_frame_id);
|
||||
replacer.SetEvictable(victim_frame_id, false);
|
||||
disk_manager->ReadPage(page_id, victim_page_ptr->GetData());
|
||||
return victim_page_ptr;
|
||||
}
|
||||
|
||||
auto BufferPoolManager::UnpinPage(page_id_t page_id, bool is_dirty) -> bool {
|
||||
#ifdef ENABLE_ADVANCED_FEATURE
|
||||
std::lock_guard<std::mutex> guard(latch);
|
||||
#endif
|
||||
if (page_table_.find(page_id) == page_table_.end()) {
|
||||
return false;
|
||||
}
|
||||
frame_id_t frame_id = page_table_[page_id];
|
||||
Page *cur_page = &pages_[frame_id];
|
||||
if (cur_page->pin_count_ <= 0) {
|
||||
return false;
|
||||
}
|
||||
cur_page->pin_count_--;
|
||||
if (cur_page->pin_count_ == 0) {
|
||||
replacer.SetEvictable(frame_id, true);
|
||||
}
|
||||
if (is_dirty) {
|
||||
cur_page->is_dirty_ = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
auto BufferPoolManager::FlushPage(page_id_t page_id) -> bool {
|
||||
#ifdef ENABLE_ADVANCED_FEATURE
|
||||
std::lock_guard<std::mutex> guard(latch);
|
||||
#endif
|
||||
frame_id_t frame_id = page_table_[page_id];
|
||||
if (page_table_.find(page_id) == page_table_.end()) {
|
||||
return false;
|
||||
}
|
||||
Page *cur_page = &pages_[frame_id];
|
||||
disk_manager->WritePage(page_id, cur_page->GetData());
|
||||
cur_page->is_dirty_ = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void BufferPoolManager::FlushAllPages() {
|
||||
for (auto &pair : page_table_) {
|
||||
FlushPage(pair.first);
|
||||
}
|
||||
disk_manager->FullyFlush();
|
||||
}
|
||||
|
||||
auto BufferPoolManager::DeletePage(page_id_t page_id) -> bool {
|
||||
#ifdef ENABLE_ADVANCED_FEATURE
|
||||
std::lock_guard<std::mutex> guard(latch);
|
||||
#endif
|
||||
if (page_table_.find(page_id) == page_table_.end()) {
|
||||
return true;
|
||||
}
|
||||
frame_id_t frame_id = page_table_[page_id];
|
||||
Page *page = &pages_[frame_id];
|
||||
if (page->pin_count_ > 0) {
|
||||
return false;
|
||||
}
|
||||
page_table_.erase(page_id);
|
||||
replacer.TryEvictExactFrame(frame_id);
|
||||
free_list_.push_back(frame_id);
|
||||
page->is_dirty_ = false;
|
||||
page->pin_count_ = 0;
|
||||
page->page_id_ = 0;
|
||||
page->ResetMemory();
|
||||
DeallocatePage(page_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
auto BufferPoolManager::FetchPageBasic(page_id_t page_id) -> BasicPageGuard {
|
||||
Page *page = FetchPage(page_id);
|
||||
if (page == nullptr) throw std::runtime_error("Buffer Pool is full!");
|
||||
return {this, page};
|
||||
}
|
||||
|
||||
auto BufferPoolManager::FetchPageRead(page_id_t page_id) -> ReadPageGuard {
|
||||
Page *page = FetchPage(page_id);
|
||||
if (page == nullptr) throw std::runtime_error("Buffer Pool is full!");
|
||||
#ifdef ENABLE_ADVANCED_FEATURE
|
||||
if (page != nullptr) {
|
||||
page->RLatch();
|
||||
}
|
||||
#endif
|
||||
return {this, page};
|
||||
}
|
||||
|
||||
auto BufferPoolManager::FetchPageWrite(page_id_t page_id) -> WritePageGuard {
|
||||
Page *page = FetchPage(page_id);
|
||||
if (page == nullptr) throw std::runtime_error("Buffer Pool is full!");
|
||||
#ifdef ENABLE_ADVANCED_FEATURE
|
||||
if (page != nullptr) {
|
||||
page->WLatch();
|
||||
}
|
||||
#endif
|
||||
return {this, page};
|
||||
}
|
||||
|
||||
auto BufferPoolManager::NewPageGuarded(page_id_t *page_id) -> BasicPageGuard {
|
||||
Page *page = NewPage(page_id);
|
||||
if (page == nullptr) throw std::runtime_error("Buffer Pool is full!");
|
||||
return {this, page};
|
||||
}
|
108
storage/src/disk_manager.cpp
Normal file
108
storage/src/disk_manager.cpp
Normal file
@ -0,0 +1,108 @@
|
||||
#include "storage/disk_manager.h"
|
||||
#include <cstring>
|
||||
#include <exception>
|
||||
#include <stdexcept>
|
||||
const size_t kPageSize = 4096;
|
||||
DiskManager::DiskManager(const std::string &file_path_, bool renew)
|
||||
: file_path(file_path_),
|
||||
first_empty_page_id(0),
|
||||
current_total_page_count(0),
|
||||
current_none_empty_page_count(0),
|
||||
raw_data_memory(nullptr),
|
||||
fp(nullptr) {
|
||||
if (renew) remove(file_path.c_str());
|
||||
fp = fopen(file_path.c_str(), "r+b");
|
||||
if (fp == nullptr) {
|
||||
// File doesn't exist, create a new one
|
||||
fp = fopen(file_path.c_str(), "w+b");
|
||||
// Initialize internal page
|
||||
first_empty_page_id = 0;
|
||||
current_total_page_count = 0;
|
||||
current_none_empty_page_count = 0;
|
||||
raw_data_memory = new char[kPageSize - meta_data_size];
|
||||
memset(raw_data_memory, 0, kPageSize - meta_data_size);
|
||||
FullyFlush();
|
||||
is_new = true;
|
||||
} else {
|
||||
// File exists, read metadata from internal page
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
fread(&first_empty_page_id, sizeof(page_id_t), 1, fp);
|
||||
fread(¤t_total_page_count, sizeof(size_t), 1, fp);
|
||||
fread(¤t_none_empty_page_count, sizeof(size_t), 1, fp);
|
||||
raw_data_memory = new char[kPageSize - meta_data_size];
|
||||
fread(raw_data_memory, kPageSize - meta_data_size, 1, fp);
|
||||
is_new = false;
|
||||
}
|
||||
page_buf = new char[kPageSize];
|
||||
}
|
||||
|
||||
DiskManager::~DiskManager() {
|
||||
Close();
|
||||
delete[] raw_data_memory;
|
||||
delete[] page_buf;
|
||||
}
|
||||
|
||||
char *DiskManager::RawDataMemory() { return raw_data_memory; }
|
||||
|
||||
size_t DiskManager::RawDatMemorySize() { return kPageSize - meta_data_size; }
|
||||
|
||||
void DiskManager::FullyFlush() {
|
||||
if (fp == nullptr) return;
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
fwrite(&first_empty_page_id, sizeof(page_id_t), 1, fp);
|
||||
fwrite(¤t_total_page_count, sizeof(size_t), 1, fp);
|
||||
fwrite(¤t_none_empty_page_count, sizeof(size_t), 1, fp);
|
||||
fwrite(raw_data_memory, kPageSize - meta_data_size, 1, fp);
|
||||
fflush(fp);
|
||||
}
|
||||
|
||||
void DiskManager::Close() {
|
||||
if (fp != nullptr) {
|
||||
FullyFlush();
|
||||
fclose(fp);
|
||||
fp = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void DiskManager::ReadPage(page_id_t page_id, char *page_data_ptr) {
|
||||
if (fp == nullptr) return;
|
||||
fseek(fp, page_id * kPageSize, SEEK_SET);
|
||||
fread(page_data_ptr, kPageSize, 1, fp);
|
||||
}
|
||||
|
||||
void DiskManager::WritePage(page_id_t page_id, const char *page_data_ptr) {
|
||||
if (fp == nullptr) return;
|
||||
fseek(fp, page_id * kPageSize, SEEK_SET);
|
||||
fwrite(page_data_ptr, kPageSize, 1, fp);
|
||||
}
|
||||
|
||||
bool DiskManager::CurrentFileIsNew() { return is_new; }
|
||||
|
||||
page_id_t DiskManager::AllocNewEmptyPageId() {
|
||||
page_id_t new_page_id;
|
||||
if (first_empty_page_id == 0) {
|
||||
// No empty page available, append a new page
|
||||
current_total_page_count++;
|
||||
new_page_id = current_total_page_count;
|
||||
fseek(fp, 0, SEEK_END);
|
||||
fwrite(page_buf, kPageSize, 1, fp);
|
||||
} else {
|
||||
new_page_id = first_empty_page_id;
|
||||
ReadPage(new_page_id, page_buf);
|
||||
memcpy(&first_empty_page_id, page_buf, sizeof(page_id_t));
|
||||
}
|
||||
current_none_empty_page_count++;
|
||||
return new_page_id;
|
||||
}
|
||||
|
||||
void DiskManager::DeallocatePage(page_id_t page_id) {
|
||||
// Add the deallocated page to the head of the empty list
|
||||
memcpy(page_buf, &first_empty_page_id, sizeof(page_id_t));
|
||||
WritePage(page_id, page_buf);
|
||||
first_empty_page_id = page_id;
|
||||
current_none_empty_page_count--;
|
||||
}
|
||||
|
||||
size_t DiskManager::CurrentTotalPageCount() { return current_total_page_count; }
|
||||
|
||||
size_t DiskManager::CurrentNoneEmptyPageCount() { return current_none_empty_page_count; }
|
173
storage/src/replacer.cpp
Normal file
173
storage/src/replacer.cpp
Normal file
@ -0,0 +1,173 @@
|
||||
#include "storage/replacer.h"
|
||||
#include <cstddef>
|
||||
LRUKReplacer::LRUKReplacer(size_t max_frame_count, size_t k_value)
|
||||
: max_frame_count(max_frame_count), k_value(k_value) {
|
||||
hash_for_record = new LRUKRecord[max_frame_count];
|
||||
for (size_t i = 0; i < max_frame_count; i++) {
|
||||
hash_for_record[i].active = false;
|
||||
}
|
||||
LRU_chain_head_guard = new LRUChainNodeType(-1, nullptr, nullptr);
|
||||
LRU_chain_tail_guard = new LRUChainNodeType(-1, nullptr, nullptr);
|
||||
LRU_chain_head_guard->next = LRU_chain_tail_guard;
|
||||
LRU_chain_tail_guard->prev = LRU_chain_head_guard;
|
||||
LRUK_chain_head_guard = new MainChainNodeType(-1, 0, nullptr, nullptr, nullptr);
|
||||
LRUK_chain_tail_guard = new MainChainNodeType(-1, 0, nullptr, nullptr, nullptr);
|
||||
LRUK_chain_head_guard->next = LRUK_chain_tail_guard;
|
||||
LRUK_chain_tail_guard->prev = LRUK_chain_head_guard;
|
||||
}
|
||||
|
||||
LRUKReplacer::~LRUKReplacer() {
|
||||
delete[] hash_for_record;
|
||||
LRUChainNodeType *ptr = LRU_chain_head_guard->next;
|
||||
while (ptr != LRU_chain_tail_guard) {
|
||||
LRUChainNodeType *tmp = ptr;
|
||||
ptr = ptr->next;
|
||||
delete tmp;
|
||||
}
|
||||
MainChainNodeType *ptr2 = LRUK_chain_head_guard->next;
|
||||
while (ptr2 != LRUK_chain_tail_guard) {
|
||||
MainChainNodeType *tmp = ptr2;
|
||||
ptr2 = ptr2->next;
|
||||
delete tmp;
|
||||
}
|
||||
delete LRU_chain_head_guard;
|
||||
delete LRU_chain_tail_guard;
|
||||
delete LRUK_chain_head_guard;
|
||||
delete LRUK_chain_tail_guard;
|
||||
}
|
||||
|
||||
void LRUKReplacer::SetEvictable(frame_id_t frame_id, bool evitable) {
|
||||
#ifdef ENABLE_ADVANCED_FEATURE
|
||||
std::lock_guard<std::mutex> guard(latch);
|
||||
#endif
|
||||
if (!hash_for_record[frame_id].active) {
|
||||
return;
|
||||
}
|
||||
if (hash_for_record[frame_id].evitable == evitable) {
|
||||
return;
|
||||
}
|
||||
hash_for_record[frame_id].evitable = evitable;
|
||||
if (evitable) {
|
||||
current_evitable_count_++;
|
||||
} else {
|
||||
current_evitable_count_--;
|
||||
}
|
||||
}
|
||||
|
||||
void LRUKReplacer::RemoveWholeFrameFromLRUKChain(MainChainNodeType *first_occurrence_ptr) {
|
||||
if (first_occurrence_ptr == nullptr) return;
|
||||
MainChainNodeType *tmp;
|
||||
while (first_occurrence_ptr != nullptr) {
|
||||
tmp = first_occurrence_ptr;
|
||||
RemoveFromList(tmp);
|
||||
first_occurrence_ptr = first_occurrence_ptr->next_self_record;
|
||||
delete tmp;
|
||||
}
|
||||
}
|
||||
|
||||
LRUKReplacer::MainChainNodeType *LRUKReplacer::AddRecordToMainChain(frame_id_t frame_id, size_t time_stamp,
|
||||
MainChainNodeType *last_node_in_main_chain) {
|
||||
MainChainNodeType *new_node = new LRUKReplacer::MainChainNodeType(frame_id, time_stamp, nullptr, nullptr, nullptr);
|
||||
if (last_node_in_main_chain != nullptr) last_node_in_main_chain->next_self_record = new_node;
|
||||
InsertAt(new_node, LRUK_chain_tail_guard->prev, LRUK_chain_tail_guard);
|
||||
return new_node;
|
||||
}
|
||||
|
||||
bool LRUKReplacer::TryEvictExactFrame(frame_id_t frame_id) {
|
||||
#ifdef ENABLE_ADVANCED_FEATURE
|
||||
std::lock_guard<std::mutex> guard(latch);
|
||||
#endif
|
||||
if (!hash_for_record[frame_id].active) {
|
||||
return false;
|
||||
}
|
||||
if (!hash_for_record[frame_id].evitable) {
|
||||
return false;
|
||||
}
|
||||
LRUChainNodeType *node = hash_for_record[frame_id].node_in_LRU_chain;
|
||||
if (node != nullptr) RemoveFromList(node);
|
||||
delete node;
|
||||
hash_for_record[frame_id].node_in_LRU_chain = nullptr;
|
||||
RemoveWholeFrameFromLRUKChain(hash_for_record[frame_id].head_node_in_main_chain);
|
||||
hash_for_record[frame_id].active = false;
|
||||
current_evitable_count_--;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LRUKReplacer::TryEvictLeastImportant(frame_id_t &frame_id) {
|
||||
#ifdef ENABLE_ADVANCED_FEATURE
|
||||
latch.lock();
|
||||
#endif
|
||||
if (current_evitable_count_ == 0) {
|
||||
#ifdef ENABLE_ADVANCED_FEATURE
|
||||
latch.unlock();
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
LRUChainNodeType *node = LRU_chain_head_guard->next;
|
||||
while (node != LRU_chain_tail_guard) {
|
||||
frame_id = node->frame_id;
|
||||
if (hash_for_record[frame_id].evitable) {
|
||||
#ifdef ENABLE_ADVANCED_FEATURE
|
||||
latch.unlock();
|
||||
#endif
|
||||
return TryEvictExactFrame(frame_id);
|
||||
}
|
||||
node = node->next;
|
||||
}
|
||||
MainChainNodeType *main_chain_node = LRUK_chain_head_guard->next;
|
||||
while (main_chain_node != LRUK_chain_tail_guard) {
|
||||
frame_id = main_chain_node->frame_id;
|
||||
if (hash_for_record[frame_id].evitable) {
|
||||
#ifdef ENABLE_ADVANCED_FEATURE
|
||||
latch.unlock();
|
||||
#endif
|
||||
return TryEvictExactFrame(frame_id);
|
||||
}
|
||||
main_chain_node = main_chain_node->next;
|
||||
}
|
||||
#ifdef ENABLE_ADVANCED_FEATURE
|
||||
latch.unlock();
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
void LRUKReplacer::RecordAccess(frame_id_t frame_id) {
|
||||
#ifdef ENABLE_ADVANCED_FEATURE
|
||||
std::lock_guard<std::mutex> guard(latch);
|
||||
#endif
|
||||
current_timestamp_++;
|
||||
if (!hash_for_record[frame_id].active) {
|
||||
hash_for_record[frame_id].active = true;
|
||||
hash_for_record[frame_id].evitable = false;
|
||||
hash_for_record[frame_id].visit_count = 1;
|
||||
hash_for_record[frame_id].head_node_in_main_chain = hash_for_record[frame_id].tail_node_in_main_chain =
|
||||
AddRecordToMainChain(frame_id, current_timestamp_, nullptr);
|
||||
hash_for_record[frame_id].node_in_LRU_chain =
|
||||
new LRUChainNodeType(frame_id, LRU_chain_tail_guard->prev, LRU_chain_tail_guard);
|
||||
InsertAt(hash_for_record[frame_id].node_in_LRU_chain, LRU_chain_tail_guard->prev, LRU_chain_tail_guard);
|
||||
} else {
|
||||
hash_for_record[frame_id].visit_count++;
|
||||
MainChainNodeType *last_occurrence_ptr = hash_for_record[frame_id].tail_node_in_main_chain;
|
||||
MainChainNodeType *new_node_in_main_chain_ptr =
|
||||
AddRecordToMainChain(frame_id, current_timestamp_, last_occurrence_ptr);
|
||||
hash_for_record[frame_id].tail_node_in_main_chain = new_node_in_main_chain_ptr;
|
||||
if (hash_for_record[frame_id].node_in_LRU_chain != nullptr) {
|
||||
RemoveFromList(hash_for_record[frame_id].node_in_LRU_chain);
|
||||
delete hash_for_record[frame_id].node_in_LRU_chain;
|
||||
hash_for_record[frame_id].node_in_LRU_chain = nullptr;
|
||||
}
|
||||
if (hash_for_record[frame_id].visit_count < k_value) {
|
||||
hash_for_record[frame_id].node_in_LRU_chain =
|
||||
new LRUChainNodeType(frame_id, LRU_chain_tail_guard->prev, LRU_chain_tail_guard);
|
||||
InsertAt(hash_for_record[frame_id].node_in_LRU_chain, LRU_chain_tail_guard->prev, LRU_chain_tail_guard);
|
||||
}
|
||||
if (hash_for_record[frame_id].visit_count > k_value) {
|
||||
MainChainNodeType *first_occurrence_ptr = hash_for_record[frame_id].head_node_in_main_chain;
|
||||
RemoveFromList(first_occurrence_ptr);
|
||||
hash_for_record[frame_id].head_node_in_main_chain = first_occurrence_ptr->next_self_record;
|
||||
delete first_occurrence_ptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t LRUKReplacer::GetCurrentEvitableCount() { return current_evitable_count_; }
|
Reference in New Issue
Block a user