cmu2023 fall project 2
project2
task1:page_guard
#include "storage/page/page_guard.h"
#include "buffer/buffer_pool_manager.h"
namespace bustub {
//noexcept表示该函数不会抛出异常
BasicPageGuard::BasicPageGuard(BasicPageGuard &&that) noexcept {
bpm_ = that.bpm_;
page_ = that.page_;
that.page_ = nullptr;
that.bpm_ = nullptr;
}
void BasicPageGuard::Drop() {
if(page_!= nullptr){
if(is_dirty_){
bpm_->UnpinPage(page_->GetPageId(), is_dirty_);
} else{
bpm_->UnpinPage(page_->GetPageId(), false);
}
page_ = nullptr;
is_dirty_ = false;
}
}
auto BasicPageGuard::operator=(BasicPageGuard &&that) noexcept -> BasicPageGuard & {
if (this != &that) {
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) {
guard_ = std::move(that.guard_);
}
return *this;
}
void ReadPageGuard::Drop() {
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) {
guard_ = std::move(that.guard_);
}
return *this;
}
void WritePageGuard::Drop() {
guard_.Drop();
}
WritePageGuard::~WritePageGuard() {
Drop();
} // NOLINT
} // namespace bustub
task2
1、extendible_htable_header_page.cpp
//===----------------------------------------------------------------------===//
//
// BusTub
//
// extendible_htable_header_page.cpp
//
// Identification: src/storage/page/extendible_htable_header_page.cpp
//
// Copyright (c) 2015-2023, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//
#include "storage/page/extendible_htable_header_page.h"
#include "common/exception.h"
namespace bustub {
void ExtendibleHTableHeaderPage::Init(uint32_t max_depth) {
max_depth_ = max_depth;
// 初始化目录页ID数组,将所有值设为无效ID
auto size = MaxSize();
for (uint32_t i = 0; i < size; ++i) {
directory_page_ids_[i] = INVALID_PAGE_ID;
}
}
auto ExtendibleHTableHeaderPage::HashToDirectoryIndex(uint32_t hash) const -> uint32_t {
if (max_depth_ == 0) {
return 0;
}
// 取开头的max_depth_个二进制数
return hash >> (sizeof(hash)*8 - max_depth_);
}
auto ExtendibleHTableHeaderPage::GetDirectoryPageId(uint32_t directory_idx) const -> uint32_t {
if (directory_idx >= static_cast<uint32_t>(1 << max_depth_)) {
throw Exception("Directory index out of bound");
}
return directory_page_ids_[directory_idx];
}
void ExtendibleHTableHeaderPage::SetDirectoryPageId(uint32_t directory_idx, page_id_t directory_page_id) {
if (directory_idx >= static_cast<uint32_t>(1 << max_depth_)) {
throw Exception("Directory index out of bound");
}
directory_page_ids_[directory_idx] = directory_page_id;
}
auto ExtendibleHTableHeaderPage::MaxSize() const -> uint32_t {
//用了移位运算符 << 来计算 2^max_depth_,对于任何整数 x,1 << x 的结果是 2^x。
return 1 << max_depth_;
}
} // namespace bustub
2、extendible_htable_directory_page.cpp
//===----------------------------------------------------------------------===//
//
// BusTub
//
// extendible_htable_directory_page.cpp
//
// Identification: src/storage/page/extendible_htable_directory_page.cpp
//
// Copyright (c) 2015-2023, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//
#include "storage/page/extendible_htable_directory_page.h"
#include <algorithm>
#include <unordered_map>
#include "common/config.h"
#include "common/logger.h"
namespace bustub {
auto ExtendibleHTableDirectoryPage::GetGlobalDepthMask() const -> uint32_t {
// 计算掩码,全局深度位的低位是 1,其余位是 0
// 例如,如果全局深度为 2,则掩码是二进制的 11(即十进制的 3)
auto depth = global_depth_;
uint32_t result = (1 << depth) - 1;
return result;
}
auto ExtendibleHTableDirectoryPage::GetLocalDepthMask(uint32_t bucket_idx) const -> uint32_t {
// 首先检查 bucket_idx 是否有效
if (bucket_idx >= static_cast<uint32_t>(1 << global_depth_)) {
throw std::out_of_range("Bucket index out of range");
}
// 获取 bucket_idx 处的局部深度
uint32_t local_depth = local_depths_[bucket_idx];
// 计算掩码,局部深度位的低位是 1,其余位是 0
return 1 << (local_depth - 1);
}
void ExtendibleHTableDirectoryPage::Init(uint32_t max_depth) {
max_depth_ = max_depth;
global_depth_ = 0;
std::fill(local_depths_, local_depths_ + (1 << max_depth), 0);
std::fill(bucket_page_ids_, bucket_page_ids_ + (1 << max_depth), INVALID_PAGE_ID);
}
auto ExtendibleHTableDirectoryPage::HashToBucketIndex(uint32_t hash) const -> uint32_t {
//先交 GlobalDepthMask、后交LocalDepthMask。
auto hash_ = hash & GetGlobalDepthMask();
return hash_;
}
auto ExtendibleHTableDirectoryPage::GetBucketPageId(uint32_t bucket_idx) const -> page_id_t {
return bucket_page_ids_[bucket_idx];
}
void ExtendibleHTableDirectoryPage::SetBucketPageId(uint32_t bucket_idx, page_id_t bucket_page_id) {
bucket_page_ids_[bucket_idx] = bucket_page_id;
}
auto ExtendibleHTableDirectoryPage::GetSplitImageIndex(uint32_t bucket_idx) const -> uint32_t {
// 获取桶的本地深度
uint32_t local_depth = GetLocalDepth(bucket_idx);
// 计算和本地深度对应的位掩码
uint32_t mask = 1 << local_depth;
// 计算分裂的镜像索引
return bucket_idx ^ mask;
}
auto ExtendibleHTableDirectoryPage::GetGlobalDepth() const -> uint32_t {
return global_depth_;
}
void ExtendibleHTableDirectoryPage::IncrGlobalDepth() {
// 增加全局深度
global_depth_++;
// 计算新的目录大小
uint32_t new_size = 1 << global_depth_;
uint32_t old_size = new_size >> 1; // 或者等于 1 << (global_depth_ - 1)
// 更新目录项
for (uint32_t i = 0; i < old_size; ++i) {
// 新的目录项是旧目录项的复制
bucket_page_ids_[old_size + i] = bucket_page_ids_[i];
local_depths_[old_size + i] = local_depths_[i];
}
}
void ExtendibleHTableDirectoryPage::DecrGlobalDepth() {
if (global_depth_ > 0) {
global_depth_--;
}
}
auto ExtendibleHTableDirectoryPage::CanShrink() -> bool {
// 如果全局深度为0,则不能再收缩
if (global_depth_ == 0) {
return false;
}
// 检查所有桶的本地深度是否都小于全局深度
for (uint32_t i = 0; i < Size(); i++) {
if (local_depths_[i] == global_depth_) {
return false;
}
}
return true;
}
auto ExtendibleHTableDirectoryPage::Size() const -> uint32_t {
// 目录的当前大小是2的global_depth_次方
return 1 << global_depth_;
}
auto ExtendibleHTableDirectoryPage::GetLocalDepth(uint32_t bucket_idx) const -> uint32_t {
return local_depths_[bucket_idx];
}
void ExtendibleHTableDirectoryPage::SetLocalDepth(uint32_t bucket_idx, uint8_t local_depth) {
auto depth __attribute__((unused)) = local_depths_[bucket_idx];
local_depths_[bucket_idx] = local_depth;
}
void ExtendibleHTableDirectoryPage::IncrLocalDepth(uint32_t bucket_idx) {
if (local_depths_[bucket_idx] < global_depth_) {
local_depths_[bucket_idx]++;
}
}
void ExtendibleHTableDirectoryPage::DecrLocalDepth(uint32_t bucket_idx) {
if (local_depths_[bucket_idx] > 0) {
local_depths_[bucket_idx]--;
}
}
} // namespace bustub
3、extendible_htable_bucket_page.cpp
//===----------------------------------------------------------------------===//
//
// BusTub
//
// extendible_htable_bucket_page.cpp
//
// Identification: src/storage/page/extendible_htable_bucket_page.cpp
//
// Copyright (c) 2015-2023, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//
#include <optional>
#include <utility>
#include "common/exception.h"
#include "storage/page/extendible_htable_bucket_page.h"
namespace bustub {
template <typename K, typename V, typename KC>
void ExtendibleHTableBucketPage<K, V, KC>::Init(uint32_t max_size) {
size_ = 0;
max_size_ = max_size;
// array_ 的初始化依赖于 KeyValue 类型的大小和页面大小限制
}
template <typename K, typename V, typename KC>
auto ExtendibleHTableBucketPage<K, V, KC>::Lookup(const K &key, V &value, const KC &cmp) const -> bool {
for (uint32_t i = 0; i < size_; ++i) {
if (cmp(array_[i].first, key) == 0) {
value = array_[i].second;
return true;
}
}
return false;
}
template <typename K, typename V, typename KC>
auto ExtendibleHTableBucketPage<K, V, KC>::Insert(const K &key, const V &value, const KC &cmp) -> bool {
if (IsFull()) {
return false;
}
// 检查键是否已存在
for (uint32_t i = 0; i < size_; ++i) {
if (cmp(array_[i].first, key) == 0) {
return false; // 该键已存在
}
}
// 插入新的键值对
array_[size_++] = std::make_pair(key, value);
return true;
}
template <typename K, typename V, typename KC>
auto ExtendibleHTableBucketPage<K, V, KC>::Remove(const K &key, const KC &cmp) -> bool {
for (uint32_t i = 0; i < size_; ++i) {
if (cmp(array_[i].first, key) == 0) {
// 找到键并删除
for (uint32_t j = i + 1; j < size_; ++j) {
array_[j - 1] = array_[j];
}
size_--;
return true;
}
}
return false;
}
template <typename K, typename V, typename KC>
void ExtendibleHTableBucketPage<K, V, KC>::RemoveAt(uint32_t bucket_idx) {
}
template <typename K, typename V, typename KC>
auto ExtendibleHTableBucketPage<K, V, KC>::KeyAt(uint32_t bucket_idx) const -> K {
return array_[bucket_idx].first;;
}
template <typename K, typename V, typename KC>
auto ExtendibleHTableBucketPage<K, V, KC>::ValueAt(uint32_t bucket_idx) const -> V {
return array_[bucket_idx].second;
}
template <typename K, typename V, typename KC>
auto ExtendibleHTableBucketPage<K, V, KC>::EntryAt(uint32_t bucket_idx) const -> const std::pair<K, V> & {
return array_[bucket_idx];;
}
template <typename K, typename V, typename KC>
auto ExtendibleHTableBucketPage<K, V, KC>::Size() const -> uint32_t {
return size_;
}
template <typename K, typename V, typename KC>
auto ExtendibleHTableBucketPage<K, V, KC>::IsFull() const -> bool {
return size_ >= max_size_;
}
template <typename K, typename V, typename KC>
auto ExtendibleHTableBucketPage<K, V, KC>::IsEmpty() const -> bool {
return size_ == 0;
}
template class ExtendibleHTableBucketPage<int, int, IntComparator>;
template class ExtendibleHTableBucketPage<GenericKey<4>, RID, GenericComparator<4>>;
template class ExtendibleHTableBucketPage<GenericKey<8>, RID, GenericComparator<8>>;
template class ExtendibleHTableBucketPage<GenericKey<16>, RID, GenericComparator<16>>;
template class ExtendibleHTableBucketPage<GenericKey<32>, RID, GenericComparator<32>>;
template class ExtendibleHTableBucketPage<GenericKey<64>, RID, GenericComparator<64>>;
} // namespace bustub
task3
//===----------------------------------------------------------------------===//
//
// BusTub
//
// disk_extendible_hash_table.cpp
//
// Identification: src/container/disk/hash/disk_extendible_hash_table.cpp
//
// Copyright (c) 2015-2023, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//
#include <iostream>
#include <string>
#include <utility>
#include <vector>
#include "common/config.h"
#include "common/exception.h"
#include "common/logger.h"
#include "common/macros.h"
#include "common/rid.h"
#include "common/util/hash_util.h"
#include "container/disk/hash/disk_extendible_hash_table.h"
#include "storage/index/hash_comparator.h"
#include "storage/page/extendible_htable_bucket_page.h"
#include "storage/page/extendible_htable_directory_page.h"
#include "storage/page/extendible_htable_header_page.h"
#include "storage/page/page_guard.h"
namespace bustub {
template <typename K, typename V, typename KC>
DiskExtendibleHashTable<K, V, KC>::DiskExtendibleHashTable(const std::string &name, BufferPoolManager *bpm,
const KC &cmp, const HashFunction<K> &hash_fn,
uint32_t header_max_depth, uint32_t directory_max_depth,
uint32_t bucket_max_size)
: bpm_(bpm),
cmp_(cmp),
hash_fn_(std::move(hash_fn)),
header_max_depth_(header_max_depth),
directory_max_depth_(directory_max_depth),
bucket_max_size_(bucket_max_size) {
this->index_name_ = name;
//初始化header页
header_page_id_ = INVALID_PAGE_ID;
auto header_guard = bpm->NewPageGuarded(&header_page_id_);
auto header_page = header_guard.AsMut<ExtendibleHTableHeaderPage>();
header_page->Init(header_max_depth_);
//初始化目录页
page_id_t directory_page_id = INVALID_PAGE_ID;
BasicPageGuard directory_guard = bpm->NewPageGuarded(&directory_page_id);
auto directory_page = directory_guard.AsMut<ExtendibleHTableDirectoryPage>();
directory_page->Init(directory_max_depth_);
//初始化bucket页
page_id_t bucket_page_id = INVALID_PAGE_ID;
BasicPageGuard bucket_guard = bpm->NewPageGuarded(&bucket_page_id);
auto bucket_page = bucket_guard.AsMut<ExtendibleHTableBucketPage<GenericKey<8>, RID, GenericComparator<8>>>();
bucket_page->Init(bucket_max_size_);
//连接header页和目录页
header_page->SetDirectoryPageId(0, directory_page_id);
directory_page->SetBucketPageId(0, bucket_page_id);
}
/*****************************************************************************
* SEARCH
*****************************************************************************/
template <typename K, typename V, typename KC>
auto DiskExtendibleHashTable<K, V, KC>::GetValue(const K &key, std::vector<V> *result, Transaction *transaction) const
-> bool {
//计算key的哈希值
uint32_t hash = Hash(key);
//先根据header_page_id_获取header页
auto header_page_data = bpm_->FetchPage(header_page_id_);
if (header_page_data == nullptr) {
throw Exception("Failed to fetch header page");
}
// 获取header_page
auto header_page = reinterpret_cast<ExtendibleHTableHeaderPage *>(header_page_data->GetData());
//使用header_page来获取目录索引
uint32_t directory_index = header_page->HashToDirectoryIndex(hash);
//用目录索引获取目录页,然后找到目錄頁的ID
page_id_t directory_page_id = header_page->GetDirectoryPageId(directory_index);
bpm_->UnpinPage(header_page_id_, false); // 取消固定header_page
auto directory_page_data = bpm_->FetchPage(directory_page_id);
if (directory_page_data == nullptr) {
throw Exception("Failed to fetch header page");
}
// 获取目录页
auto directory_page = reinterpret_cast<ExtendibleHTableDirectoryPage *>(directory_page_data->GetData());
//使用directory_page来获取目录索引
auto bucket_index = directory_page->HashToBucketIndex(hash);
// 根据目录索引找到桶页的ID
page_id_t bucket_page_id = directory_page->GetBucketPageId(bucket_index);
bpm_->UnpinPage(directory_page_id, false);// 取消固定directory_page_id
//获取桶页并使用Lookup函数查找键
auto bucket_page_data = bpm_->FetchPage(bucket_page_id);
if (bucket_page_data == nullptr) {
throw Exception("Failed to fetch bucket page");
}
auto bucket_page = reinterpret_cast<ExtendibleHTableBucketPage<K, V, KC> *>(bucket_page_data->GetData());
V value;
bool found = bucket_page->Lookup(key, value, cmp_);
if (found) {
result->push_back(value);
}
bpm_->UnpinPage(bucket_page_id, false); // 取消固定桶页
return found;
}
/*****************************************************************************
* INSERTION
*****************************************************************************/
template <typename K, typename V, typename KC>
auto DiskExtendibleHashTable<K, V, KC>::Insert(const K &key, const V &value, Transaction *transaction) -> bool {
//计算key的哈希值
uint32_t hash = Hash(key);
//先根据header_page_id_获取header页
auto header_read_guard= bpm_->FetchPageRead(header_page_id_);
auto header_page_data = bpm_->FetchPage(header_page_id_);
if (header_page_data == nullptr) {
throw Exception("Failed to fetch header page");
}
// 获取header_page
auto header_page = reinterpret_cast<ExtendibleHTableHeaderPage *>(header_page_data->GetData());
//使用header_page来获取目录索引
auto directory_index = header_page->HashToDirectoryIndex(hash);
//用目录索引获取目录页,然后找到目錄頁的ID
page_id_t directory_page_id = header_page->GetDirectoryPageId(directory_index);
header_page_data->RUnlatch();
header_read_guard.Drop();
bpm_->UnpinPage(header_page_id_, false); // 取消固定header_page
auto directory_read_guard= bpm_->FetchPageRead(directory_page_id);
auto directory_page_data = bpm_->FetchPage(directory_page_id);
// 获取目录页
auto directory_page = reinterpret_cast<ExtendibleHTableDirectoryPage *>(directory_page_data->GetData());
//使用directory_page来获取目录索引
auto bucket_index = directory_page->HashToBucketIndex(hash);
// 根据目录索引找到桶页的ID
page_id_t bucket_page_id = directory_page->GetBucketPageId(bucket_index);
directory_page_data->RUnlatch();
directory_read_guard.Drop();
bpm_->UnpinPage(directory_page_id, false);// 取消固定directory_page_id
auto bucket_page_data = bpm_->FetchPage(bucket_page_id);
//获取桶页
auto bucket_page = reinterpret_cast<ExtendibleHTableBucketPage<K, V, KC> *>(bucket_page_data->GetData());
//進行插入鍵值
bool insert_result = InsertToNewDirectory(header_page, directory_index, hash, key, value);
//如果插入成功,将bucket_page_id写回目录页
//插入不成功,检查是否需要扩展目录页
if (insert_result) {
bpm_->UnpinPage(bucket_page_id, true); // 标记为脏并取消固定桶页
} else {
// Step 1: 检查是否需要扩展全局目录
if (directory_page->GetLocalDepth(bucket_index) == directory_page->GetGlobalDepth()) {
// 需要扩展全局目录,因为全局深度等于局部深度
if(directory_page->GetGlobalDepth() == directory_max_depth_){
return false;
}
directory_page->IncrGlobalDepth();
}
// 进行桶分裂
uint32_t original_bucket_idx = directory_page->HashToBucketIndex(hash);
uint32_t split_bucket_idx = directory_page->GetSplitImageIndex(original_bucket_idx);
//初始化新bucket页
page_id_t new_bucket_page_id = INVALID_PAGE_ID;
BasicPageGuard new_bucket_guard = bpm_->NewPageGuarded(&new_bucket_page_id);
auto new_bucket_page = new_bucket_guard.AsMut<ExtendibleHTableBucketPage<K, V, KC>>();
new_bucket_page->Init(bucket_max_size_);
// 更新原始和新分裂桶的局部深度
directory_page->IncrLocalDepth(original_bucket_idx);
directory_page->SetLocalDepth(split_bucket_idx, directory_page->GetLocalDepth(original_bucket_idx));
auto new_local_depth = directory_page->GetLocalDepth(original_bucket_idx);
auto local_depth_mask = directory_page->GetLocalDepthMask(original_bucket_idx);
directory_page->SetBucketPageId(split_bucket_idx, new_bucket_page_id);
// 局部深度已经增加,且split_bucket_idx是新桶对应的目录索引,進行目錄更新
UpdateDirectoryMapping(directory_page, split_bucket_idx, new_bucket_page_id, new_local_depth, local_depth_mask);
//重新分配键到原桶和新桶
auto size = bucket_page->Size();
for (uint32_t i = 0; i < size; ++i) {
// 将键值对分配到原桶和新桶
auto bucket_key = bucket_page->KeyAt(i);
uint32_t key_hash = Hash(bucket_key);
uint32_t bucketIndex = directory_page->HashToBucketIndex(key_hash);
// 确定是否应该在当前桶中
if (split_bucket_idx == bucketIndex) {
// 键应该存储在新桶中
bucket_page->Remove(bucket_key,cmp_);
new_bucket_page->Insert(bucket_page->KeyAt(i), bucket_page->ValueAt(i), cmp_);
}
}
// 在分裂完成后,再次尝试插入
insert_result = Insert(key, value);
}
// WritePageGuard的析构函数会自动处理页面的解固定和脏页写回操作
return insert_result;
}
template <typename K, typename V, typename KC>
auto DiskExtendibleHashTable<K, V, KC>::InsertToNewDirectory(ExtendibleHTableHeaderPage *header, uint32_t directory_idx,
uint32_t hash, const K &key, const V &value) -> bool {
// 计算新的目录索引,这里假设已经进行了全局深度的增加
uint32_t new_directory_index = header->HashToDirectoryIndex(hash);
// 获取新的目录页ID
page_id_t new_directory_page_id = header->GetDirectoryPageId(new_directory_index);
// 获取新的目录页
auto new_directory_page_data = bpm_->FetchPage(new_directory_page_id);
if (new_directory_page_data == nullptr) {
throw Exception("Failed to fetch new directory page");
}
auto new_directory_page = reinterpret_cast<ExtendibleHTableDirectoryPage *>(new_directory_page_data->GetData());
// 使用新的目录页进行插入
uint32_t new_bucket_idx = new_directory_page->HashToBucketIndex(hash);
bool insert_result = InsertToNewBucket(new_directory_page, new_bucket_idx, key, value);
// 完成操作,释放页面
bpm_->UnpinPage(new_directory_page_id, insert_result); // 如果插入成功,标记页面为脏
return insert_result;
}
template <typename K, typename V, typename KC>
auto DiskExtendibleHashTable<K, V, KC>::InsertToNewBucket(ExtendibleHTableDirectoryPage *directory, uint32_t bucket_idx,
const K &key, const V &value) -> bool {
// 获取桶页面ID
page_id_t bucket_page_id = directory->GetBucketPageId(bucket_idx);
// 获取桶页面
auto bucket_page_data = bpm_->FetchPage(bucket_page_id);
if (bucket_page_data == nullptr) {
throw Exception("Failed to fetch bucket page");
}
auto bucket_page = reinterpret_cast<ExtendibleHTableBucketPage<K, V, KC> *>(bucket_page_data->GetData());
// 尝试插入键值对
bool insert_result = bucket_page->Insert(key, value, cmp_);
// 完成操作,释放页面
bpm_->UnpinPage(bucket_page_id, insert_result); // 如果插入成功,标记页面为脏
return insert_result;
}
template <typename K, typename V, typename KC>
void DiskExtendibleHashTable<K, V, KC>::UpdateDirectoryMapping(ExtendibleHTableDirectoryPage *directory,
uint32_t new_bucket_idx, page_id_t new_bucket_page_id,
uint32_t new_local_depth, uint32_t local_depth_mask) {
for (uint32_t i = 0; i < (1U << directory->GetGlobalDepth()); ++i) {
// 检查目录条目是否需要更新为指向新桶
// 如果目录项对应的是原桶
if (directory->GetBucketPageId(i) == directory->GetBucketPageId(new_bucket_idx)) {
if (i & local_depth_mask) {
// 如果这个目录项的在新局部深度位上的值为1,应该指向新桶
directory->SetBucketPageId(i, new_bucket_page_id);
directory->SetLocalDepth(i, new_local_depth);
} else {
// 否则,它仍然指向原桶,但其局部深度需要更新
directory->SetLocalDepth(i, new_local_depth);
}
}
}
}
/*****************************************************************************
* REMOVE
*****************************************************************************/
template <typename K, typename V, typename KC>
auto DiskExtendibleHashTable<K, V, KC>::Remove(const K &key, Transaction *transaction) -> bool {
//计算key的哈希值
uint32_t hash = Hash(key);
//先根据header_page_id_获取header页
auto header_page_data = bpm_->FetchPage(header_page_id_);
// 获取header_page
auto header_page = reinterpret_cast<ExtendibleHTableHeaderPage *>(header_page_data->GetData());
//使用header_page来获取目录索引
auto directory_index = header_page->HashToDirectoryIndex(hash);
//用目录索引获取目录页,然后找到目錄頁的ID
page_id_t directory_page_id = header_page->GetDirectoryPageId(directory_index);
if(directory_page_id == INVALID_PAGE_ID){
return false;
}
bpm_->UnpinPage(header_page_id_, false); // 取消固定header_page
auto directory_page_data = bpm_->FetchPage(directory_page_id);
// 获取目录页
auto directory_page = reinterpret_cast<ExtendibleHTableDirectoryPage *>(directory_page_data->GetData());
//使用directory_page来获取目录索引
auto bucket_index = directory_page->HashToBucketIndex(hash);
// 根据目录索引找到桶页的ID
page_id_t bucket_page_id = directory_page->GetBucketPageId(bucket_index);
if(bucket_page_id == INVALID_PAGE_ID){
return false;
}
bpm_->UnpinPage(directory_page_id, false);// 取消固定directory_page_id
auto bucket_page_data = bpm_->FetchPage(bucket_page_id);
//获取桶页
auto bucket_page = reinterpret_cast<ExtendibleHTableBucketPage<K, V, KC> *>(bucket_page_data->GetData());
if (bucket_page->Remove(key, cmp_)) {
if(bucket_page->IsEmpty()) {
bpm_->DeletePage(bucket_page_id);
directory_page->DecrLocalDepth(bucket_index);
auto split_index = directory_page->GetSplitImageIndex(bucket_index);
if (directory_page->GetLocalDepth(split_index) == (directory_page->GetLocalDepth(bucket_index)+1)) {
directory_page->DecrLocalDepth(split_index);
for (uint32_t i = 0; i < (1U << directory_page->GetGlobalDepth()); ++i) {
if (directory_page->GetBucketPageId(i) == bucket_page_id) {
directory_page->SetBucketPageId(i, directory_page->GetBucketPageId(bucket_index));
}
}
directory_page->SetBucketPageId(bucket_index, INVALID_PAGE_ID);
bpm_->DeletePage(bucket_page_id);
bpm_->UnpinPage(directory_page_id, false);
}
if (directory_page->CanShrink()) {
// 如果目录页可以收缩,那么就收缩
auto ole_global_depth = directory_page->GetGlobalDepth();
directory_page->DecrGlobalDepth();
auto new_global_depth = directory_page->GetGlobalDepth();
for (uint32_t i = (1U << new_global_depth); i < (1U << ole_global_depth); ++i) {
directory_page->SetBucketPageId(i, INVALID_PAGE_ID);
}
}
}
// 如果成功删除,标记页面为脏
bpm_->UnpinPage(bucket_page_id, true);
return true;
}
return false;
}
template class DiskExtendibleHashTable<int, int, IntComparator>;
template class DiskExtendibleHashTable<GenericKey<4>, RID, GenericComparator<4>>;
template class DiskExtendibleHashTable<GenericKey<8>, RID, GenericComparator<8>>;
template class DiskExtendibleHashTable<GenericKey<16>, RID, GenericComparator<16>>;
template class DiskExtendibleHashTable<GenericKey<32>, RID, GenericComparator<32>>;
template class DiskExtendibleHashTable<GenericKey<64>, RID, GenericComparator<64>>;
} // namespace bustub